- Lab
- Core Tech

Guided: Data Fetching and API Routes in Next.js 14
This hands-on lab will guide you through the essentials of data fetching and API route creation in Next.js 14. Using the new App Router, you'll learn to implement Static Site Generation (SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR) through a series of practical steps. Additionally, you'll build API routes for CRUD operations, enhancing your skills in creating scalable and efficient web applications. By the end of the lab, you'll be well-prepared to tackle advanced development challenges with a solid foundation in Next.js 14's data fetching and API routing capabilities.

Path Info
Table of Contents
-
Challenge
Introduction
Welcome to this Code Lab, Guided: Data Fetching and API Routes in Next.js 14. This lab is designed for web developers or learners eager to deepen their knowledge and understanding of Next.js 14, particularly in data fetching and building robust API routes using the new App Router. Throughout this lab, you will engage in practical exercises that take you from the basics of data fetching to advanced API routing techniques. You'll learn to implement various data-fetching strategies like Static Site Generation(SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR). Additionally, you'll gain hands-on experience creating and managing API routes to perform CRUD operations. By the end of this Code Lab, you will have a solid understanding of utilising the App Router in Next.js 14 to its fullest potential, enabling you to build scalable and efficient web applications. Whether you want to refine your skills or tackle real-world development challenges, this lab will equip you with the knowledge and practical experience necessary to succeed. info> Code Solutions : You can find the final code of each step inside the
__solution/codes
folder. For example, the__solution/codes/step1_final_code.ts
file will have the final code of step 1.info> Image Solutions : You can also find the image depicting the lab's state inside the
__solution/images
folder. For example,__solution/images/step_1_final_output.png
will have the image depicting the final state of step 1. Data store using lowdb : Lowdb, a lightweight JSON database, is used in this lab to efficiently store and manage data while you build and interact with the API routes. The database is already configured, and you can access the JSON data file atdata/db.json
. API Endpoint using json-server : In this lab, we'll use json-server to create an API endpoint athttp://localhost:4000/api/tasks/
, utilisingdata/db.json
to demonstrate various data-fetching techniques in Next.js 14. You will also create an API endpoint using Next.js 14 that is similar to it. -
Challenge
Step 1: GET Request
Create an API GET Route in Next.js
In this step, you'll create an API GET Route using Next.js' file-based routing system. This functionality will return all the task items in the data source. info> The code above sets up an API route that responds to the GET requests made to the route
api/tasks
.Async GET Function
The asynchronous function above is triggered when an HTTP GET request is made to this API route. When a GET request is made to the route, it returns a JSON array of task objects. In this example, the tasks are hard-coded but might be fetched from a database or another data source in a real-world scenario.
The function is named GET because Next.js follows this convention to handle GET requests at this endpoint. Other supported methods include POST, PUT, PATCH, and DELETE.
NextRequest
This utility class provided by Next.js encapsulates the HTTP request details. It includes methods to get query parameters, headers, body, etc.NextResponse
This utility class provided by Next.js allows you to construct and return HTTP responses in API routes.Task
This is a TypeScript interface that defines the structure of a Task object. It contains three specific fields: id, title, and completed.npm run dev
Then, navigate to the URL
http://localhost:3000/api/tasks
in your Web Browser tab.You should see the tasks displayed as shown in the image below.
-
Challenge
Step 2: Dynamic Data
Change Data For API Request to be Dynamic From Data Source
For this step, you'll replace the hardcoded data from Step 1 with dynamic data fetched from a JSON database.
Explanation of above code The imported `getAllTasks` function will be used to get all the tasks from the database. The import statement also includes the `addNewTask` functions, which will be used in the upcoming steps. info> The code above replaces hardcoded tasks with dynamic data fetched from a data source using the `getAllTasks` function.Real world scenario: Data sources
In this lab, the data is fetched from a JSON database, but in a real-world scenario, the data could come from various sources such as an SQL database, an API endpoint, a GraphQL server, or other external services.You should see the task list displayed as shown in the image below. The database has been pre-populated with the task list on your screen.
In the next step, you'll create a POST request to add new tasks.
-
Challenge
Step 3: POST Request
Create an API POST Route to Create New Tasks
In this step, you will create an API Post route to create new tasks.
Explanation of above code
The above code retrieves the JSON data from the POST request and checks if the data is valid. If the data is invalid, it returns a 400 response with the message `Invalid data`.Practical validation
You are using simple validation for this lab; however, in a real-life scenario, it's more common to use a third-party package, such as Zod, for more robust and scalable validation.Explanation of above code
The above code retrieves the new task from the POST request body and adds it to the JSON database using the `addNewTask` function, which was imported in the earlier step. After that, it responds with the newly created task and a 201 status code, indicating that the request was successfully processed and a new resource was created.workspace $ curl --location 'http://localhost:3000/api/tasks' --header 'Content-Type: application/json' --data '{ "title": "Wash clothes", "completed": false }' {"id":3,"title":"Wash clothes","completed":false}workspace $ ``` Navigate to the URL `http://localhost:3000/api/tasks` in your Web Browser tab. You should see the task list, including the newly created task, as shown in the image below. If the new task is not visible, scroll down in your browser to view it. 
-
Challenge
Step 4: GET Single Task
Create an API GET Route to Get a Single Task
Now you'll create a dynamic API GET Route using Next.js' file-based dynamic routing system. This functionality will return a single task from the data source. info> The above code sets up an API route to handle
GET
requests sent to theapi/tasks/<id>
endpoint. The second argument of the function retrieves the dynamic ID from the URL. When a GET request is made, the function searches the database for the task with the providedid
and returns it.The
GET
function will be completed in the next task. ThegetTask
function has been imported to get the single task. Also, the functionsupdateTask
anddeleteTask
will be used in the following steps.Close the
app/api/tasks/route.ts
file in your editor to avoid confusion. Navigate to the URLhttp://localhost:3000/api/tasks/1
in your Web Browser.You should be able to see the task with an
id
of 1, as demonstrated in the image below. -
Challenge
Step 5: PUT Request
Create an API PUT Route to Update an Existing Task
In this step, you will create an API PUT route to update an existing task.
Explanation of above code
The code above retrieves the JSON data from the PUT request and checks whether the data is valid. If the data is invalid, it returns a 400 response with the message `Invalid data`.Explanation of above code
The above code updates an existing task in the JSON database using the data from the PUT request body. The `updateTask` function, imported in an earlier step, handles the update. After the update, the code checks if the task was successfully updated. If not, it returns a 404 status with an `Invalid data` message. If successful, it returns the updated task.workspace $ curl --location --request PUT 'http://localhost:3000/api/tasks/1' --header 'Content-Type: application/json' --data '{ "title": "Read a chapter of a book", "completed": true }' {"id":1,"title":"Read a chapter of a book","completed":true}workspace $
Now, navigate to the URL
http://localhost:3000/api/tasks/1
in your Web Browser.You should see the updated task with the completed flag set to true for the task with
id
1, as shown in the image below. -
Challenge
Step 6: Delete Request
Create an API DELETE Route to Delete an Existing Task
For this step, you will create an API DELETE route to delete an existing task.
Explanation of above code
The above code deletes an existing task using the dynamic id provided in the params. It checks whether the task was successfully deleted. If not, it returns a message `Invalid data` with a 404 status code. Then, it returns a response with the information that the task has been successfully deleted.workspace $ curl --location --request DELETE 'http://localhost:3000/api/tasks/1' {"message":"Task with id 1 deleted"}workspace $ ``` Now, navigate to the URL `http://localhost:3000/api/tasks` in your Web Browser. You should see the remaining tasks in the list, with the task that had ID 1 deleted, as shown in the image below. 
-
Challenge
Data Fetching Techniques
Understanding Data Fetching Techniques in Next.js
Before diving into upcoming data fetching steps, let's get some ideas about data fetching techniques in Next.js. Next.js provides three data-fetching strategies to optimise performance and user experience in server-side rendering. Here's a brief overview of the essential methods:
1. Static Site Generation (SSG)
SSG pre-renders pages at build time, resulting in highly performant static pages.
- Page rendered: On build time
- Content freshness: Stale until rebuild if data is changed
- Example use case: A blog where an article doesn’t change frequently
- Advantages: Fast loading times, scalable
- Limitations: Stale data after data is changed, requires rebuilding for the update, not suitable for frequently changing data
2. Server Side Rendering (SSR)
SSR generates pages on each request, ensuring the content is always up-to-date.
- Page rendered: On request
- Content freshness: Always fresh
- Example use case: E-commerce sites displaying the latest price and stock levels
- Advantages: No rebuild required, and always fresh data
- Limitations: Slower compared to SSG, increased server load
3. Incremental Static Regeneration (ISR)
ISR offers a hybrid approach, combining SSG's speed with SSR's flexibility.
- Page rendered: Build time + revalidation
- Content freshness: Fresh after revalidation
- Example use case: An event listing page that updates events and dates after a specific interval
- Advantages: Balance between SSR and SSG, reduced server load compared to SSR, flexible and scalable
- Limitations: Slight delay in content updates and the configuration of revalidation times
-
Challenge
Step 7: Static Site Generation
Creating Static Page with Static Data Fetching
You will now create a statically rendering page with static data fetching. This type of rendering is called Static Site Generation(SSG). The route of the page will be /tasks . The code above imports the
Task
interface and creates thegetTaskData
function, which uses the fetch method to get the list of tasks.info> Using
fetch(url)
orfetch(url, { cache: 'force-cache' })
will render the page as SSG (Static Site Generation) when the site is built. The{ cache: 'force-cache' }
option is the default for the second argument in the fetch function. This means Next.js will generate the page during the build process, and it won't update even if the data changes later, potentially serving outdated information. This method is best for content that doesn’t change often, like blog posts, making it an excellent example of static site generation.Explanation of above code The above code retrieves the task list and displays it with a timestamp indicating when the page was rendered. In an SSG (Static Site Generation) scenario, the timestamp will reflect when the page was generated during the build process. The command above will clear the pre-built cache and rebuild the application. Please wait a few minutes, as building a Next.js application may take some time.Once done, you should see the
/tasks
route created in the terminal, with a circle indicating that it is a static site, as shown in the image below.Now, stop the current process by pressing
Ctrl + C
in the first terminal, and then run the following command in the same terminal to start the server athttp://localhost:3000/
npm run start ``` Now, navigate to the URL `http://localhost:3000/tasks` in your Web Browser. You should see the task list as shown in the image below. info> Notice that the timestamp won’t change when you refresh the page, and the data won’t update if you add more tasks. This is because the page was generated during the build process using the Static Site Generation (SSG) rendering technique. 
-
Challenge
Step 8: Server Side Rendering
In this step, you'll change the page
/tasks
from statically rendering to a server-side rendering page(SSR).SSR pages are dynamic and created on request rather than during build time. This is implemented when fresh data needs to be served on every request. For instance, when showing the latest prices on an e-commerce website. info> In the above task, adding
{cache: 'no-store'}
as the second argument in thefetch
function ensures that the fetched data is not stored, making it dynamic for each request and resulting in dynamic page rendering. The command above will clear the pre-built cache and rebuild the application. Please wait a few minutes, as building a Next.js application may take some time.info> You should see that the tasks page has been rendered as a dynamic page with an ƒ sign in front of it, as shown in the image below.
Now, stop the current process by pressing
Ctrl + C
in the first terminal, and then run the following command in the same terminal to start the server athttp://localhost:3000/
.npm run start
Next, Navigate to the URL
http://localhost:3000/tasks
in the browser and refresh the browser a couple of times. You should be able to view the task list with an updated timestamp on every request. After executing the above curl command, you should get a response in your terminal with message{"id":X,"title":"Plan weekend trip","completed":false}
letting you know that the execution was successful. Now, navigate to the URLhttp://localhost:3000/tasks
in the Web Browser.You should be able to view that the task list has been updated, as shown in the image below. If the new task is not visible, scroll down in your browser to view it.
-
Challenge
Step 9: Incremental Static Regeneration
Now you'll change the page
/tasks
from the server-side rendering page to an incremental static regeneration page(ISR).ISR is a mix of SSR and SSG where data fetch is invalidated at specified intervals. So, after the specific interval, the page is re-rendered. This approach is great for cases where data can be updated at certain intervals and do not need to be updated on every request. info> In the above updated code,
{ next: { revalidate: 60 }}
configures the data to be invalidated and refreshed every 60 seconds, enabling Incremental Static Regeneration (ISR) for the page. This means the page's static content will be updated with fresh data at regular intervals, without needing to rebuild the entire application. The command above will clear the pre-built cache and rebuild the application. Please wait a few minutes, as building a Next.js application may take some time.info> You should see the
/tasks
route listed in the terminal, with a circle indicating that it is a static site, as shown in the image below. However, remember that its data will be revalidated at the specified interval.Now, stop the current process by pressing
Ctrl + C
in the first terminal, and then run the following command in the same terminal to start the server athttp://localhost:3000/tasks
.npm run start
info> You should get a response in your terminal with message
{"id":X,"title":"Walk the dog","completed":false}
letting you know that the execution was successful. Now, navigate to the URLhttp://localhost:3000/tasks
in the Web Browser after 60 seconds.You should be able to view that the task list has been updated, as shown in the image below. If the new task is not visible, scroll down in your browser to view it.
Congratulations! You have successfully completed the lab.
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.