Vercel Logo

Tour the Next.js Starter

The Next.js app is already working. Run it and you'll see a furniture listing page with eight items, a clean layout, in-stock badges. It looks real. The data isn't. It's a hardcoded array sitting right in the page component.

That's what we're going to replace. But first, let's see what we're working with.

Outcome

Get the Next.js starter running locally and locate the mock data that will be replaced by a real API call.

Fast Track

  1. cd starter && npm install
  2. npm run dev
  3. Open http://localhost:3000

Hands-On

Install and run

cd starter
npm install
npm run dev

You'll see Turbopack start up. Next.js 16 uses it as the default bundler:

▲ Next.js 16.0.0 (Turbopack)
- Local:        http://localhost:3000
- Network:      http://192.168.x.x:3000

✓ Starting...
✓ Ready in 612ms

Open http://localhost:3000. You'll see the Hazel Home storefront with all eight furniture items displayed.

Read the page component

Open starter/app/page.tsx. The relevant part is at the top:

const mockItems: Item[] = [
  { id: 1, name: "Fernwood Sectional", category: "Seating", price: 2499, in_stock: true },
  { id: 2, name: "Knotted Oak Coffee Table", category: "Tables", price: 849, in_stock: true },
  // ...
];
 
export default function Home() {
  return (
    <>
      <h2>All Furniture</h2>
      <div>
        {mockItems.map((item) => (
          // ...
        ))}
      </div>
    </>
  );
}

The component is synchronous. No async, no fetch. It maps over a local array and renders cards. The whole thing works without a network request, which is exactly why it's the starter state.

In Section 2, we'll swap mockItems for a fetch call to /api/items. The component markup won't change at all. Just where the data comes from.

Check the project layout

The root of starter/ has two halves living side by side:

starter/
├── api/
│   └── index.py          # FastAPI lives here
├── app/                  # Next.js app router
│   ├── globals.css
│   ├── layout.tsx
│   └── page.tsx
├── package.json          # Next.js dependencies
├── pyproject.toml        # Python dependencies
├── next.config.ts
├── postcss.config.mjs
└── tsconfig.json

Python on one side, JavaScript on the other, same project root. When you deploy, Vercel sees both and treats the api/ folder as Python functions while everything else is the Next.js app.

Check the project config

Open starter/package.json:

{
  "dependencies": {
    "next": "^16.0.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  }
}

And starter/app/layout.tsx has the shell: the header, body wrapper, and global styles. You won't need to touch this file.

Tailwind v4

This project uses Tailwind CSS v4, which has a simpler setup than v3. The entire configuration is a single import in globals.css: @import "tailwindcss". No config file, no content paths.

Try It

With both apps running simultaneously, FastAPI on port 8000 and Next.js on port 3000, open a second terminal and confirm both are up:

curl http://localhost:8000/api/items | head -c 100
[{"id":1,"name":"Fernwood Sectional","category":"Seating","price":2499.0,"in_stock":true}
curl http://localhost:3000 -s -o /dev/null -w "%{http_code}"
200

Two working apps on two ports. Not connected yet.

You can leave these dev servers running or stop them. Section 2 opens by switching to vercel dev, which replaces both with a single command.

Troubleshooting

Port 3000 already in use: Next.js will automatically try port 3001 if 3000 is taken. You'll see "ready on http://localhost:3001" in the terminal. The app still works, just on a different port.

Node version error: Next.js 16 requires Node.js 18.17 or later. Run node --version to check. If you're below that, update via nodejs.org or use a version manager like nvm.

Done-When

  • http://localhost:3000 shows the furniture listing page
  • You can locate the mockItems array in starter/app/page.tsx
  • Both apps are running at the same time without port conflicts

Solution

The starter page component with mock data in place:

// starter/app/page.tsx
const mockItems: Item[] = [
  { id: 1, name: "Fernwood Sectional", category: "Seating", price: 2499, in_stock: true },
  { id: 2, name: "Knotted Oak Coffee Table", category: "Tables", price: 849, in_stock: true },
  { id: 3, name: "Garrison Bookshelf", category: "Storage", price: 629, in_stock: false },
  { id: 4, name: "The Long Table", category: "Tables", price: 1199, in_stock: true },
  { id: 5, name: "Pivot Desk Chair", category: "Seating", price: 449, in_stock: true },
  { id: 6, name: "Ember Side Table", category: "Tables", price: 299, in_stock: true },
  { id: 7, name: "Stacked Nightstand", category: "Storage", price: 389, in_stock: false },
  { id: 8, name: "Canvas Floor Lamp", category: "Lighting", price: 219, in_stock: true },
];
 
export default function Home() {
  return (
    <>
      <h2>All Furniture</h2>
      <div>{mockItems.map((item) => ...)}</div>
    </>
  );
}

Was this helpful?

supported.