# nuxt/hackernews: a reference application for what Nuxt can do

> The Nuxt Hacker News clone is a small, complete application that shows server-side rendering, code splitting, prefetching and a Vitest setup with three test projects, deployable to Cloudflare Pages with a single build command. It is a template to read and copy rather than a product to install.

**nuxt/hackernews** — HackerNews clone built with Nuxt.

- Repository: https://github.com/nuxt/hackernews
- Website: https://hn.nuxt.dev
- Stars: 1,436 · Forks: 281
- Language: TypeScript
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/nuxt-hackernews

## A reference application, and where it came from

The nuxt/hackernews repository is a Hacker News clone built with Nuxt, and it is deployed at `hn.nuxt.dev` as a live demo.

What makes it worth reading is that it is small and complete. There is a list of stories, a story page, and the data to fill them, which is exactly the size of application where a framework's decisions are visible. A team that wants to know how Nuxt handles routing, data fetching, code splitting and server rendering can read the whole thing, and there is a demo to compare against.

The lineage is stated in the credits. The repository is originally ported from `vue-hackernews-2.0`, the Vue version of the same application, so the structure of the project is inherited from an earlier Vue implementation rather than designed from scratch. The author is Evan You, and the contributors listed in the package metadata are Sebastien Chopin, Pooya Parsa and Anthony Fu, which are the same names that recur in the Nuxt and Vue ecosystems.

The project is MIT licensed, the primary language is TypeScript, the default branch is `main`, and the last push was on 2026-10-17. There are no GitHub releases, which is right for a template whose value is in its source rather than in its versions.

There is also a `nuxt2` branch, and the README points anyone who wants the older version at it. Keeping a second major version of a reference application on a branch rather than in the history is a reasonable way to handle a framework migration, and it is a reminder that this application has been through at least one.

## Four commands, and a dev server on port 3000

The build section is the whole of the setup, and it is written for a reader who has never used Nuxt.

```bash
# install dependencies
npm install # or yarn

# serve in dev mode, with hot reload at localhost:3000
npm run dev

# build for production (server-side rendering)
npm run build

# serve in production mode (server-side rendering)
npm start

# validate and fix with ESLint (with Prettier)
npm run lintfix
```

The requirement line says Node.js 14 or later, and the comments in the block carry the important distinction: the dev server is a hot-reloading development environment, while `build` and `start` are the server-side rendered production pair. That is the part that trips people up with a universal framework, because the development server and the production server are not the same thing, and the thing that is deployed is the output of the build.

The scripts in the package metadata are more precise than the README. `dev` is `nuxt dev`, `build` is `nuxt build`, `start` is `nuxt start`, and `lint` is `eslint .`. There are also `postinstall`, which runs `nuxt prepare`, and a set of test scripts: `test` runs `vitest run`, and there are `test:unit`, `test:nuxt` and `test:e2e`, each running Vitest with a different project selected.

The repository layout matches a Nuxt application, with `app/` for the application code, `server/` for the server routes, `public/` for static assets, `utils/` and `types/` for shared code, `test/` for the tests, and the configuration files `nuxt.config.ts`, `vitest.config.ts`, `eslint.config.mjs` and `tsconfig.json`. There is also a `.nuxtrc`, a `.node-version` file and a `renovate.json` for dependency updates.

## Nitro is what makes the deployment claim true

The features list has one line that is really a deployment story: deploys anywhere with zero config, for Vercel, Netlify, Cloudflare and the rest, powered by Nitro.

Nitro is the server layer that the framework builds on, and the claim it enables is that the same build output runs on any of the supported platforms. The demo makes that concrete, because the README says the demo is hosted on Cloudflare Pages with NuxtHub and that it takes `npm run build`. There is no platform specific configuration to write, and no separate deployment branch to maintain, which is the difference between a framework that targets one host and one that targets all of them.

The other two feature lines are about the same idea from different angles. Server Side Rendering is the default mode of the production build, and code splitting and prefetch and preload of JavaScript, DNS and data are what make an application feel like a native one rather than a page that loads. Prefetching DNS is the detail that stands out, because it removes a round trip that most people never think about, and it is only possible because the framework knows what the next page will need before the reader gets there.

The performance claim in the README is a Lighthouse score of 100 out of 100 for the story page at `hn.nuxt.dev/news/1`, measured on a Slow 4G connection with a Moto G4 device profile. That is one page, one page load and one configuration of a network, and it is the kind of number that is worth reproducing rather than accepting, because it depends on the page, the origin and the moment it was measured. What it does demonstrate is that the technique is capable of it: a server-rendered document, no client-side data fetching, and prefetching of what comes next.

## Three Vitest projects, and the framework's own test utilities

The test setup is the part of a template that most often gets copied without being understood, so it is worth reading closely.

There are three Vitest projects, and the scripts name them: `test:unit` runs Vitest with the unit project, `test:nuxt` runs the nuxt project, and `test:e2e` runs the e2e project. The distinction is the interesting bit, because it reflects three different levels of what is being tested. A unit test exercises a function or a component in isolation. A nuxt test runs inside the framework's own environment, where the composables, the router and the auto-imports exist. An end to end test drives the application the way a browser does.

The supporting dependencies tell you how each is done. `@nuxt/test-utils` is the framework's own testing package, `@vue/test-utils` is the component testing library, and `happy-dom` provides a DOM implementation in JavaScript rather than a real browser, which is what makes the fast levels fast. Vitest itself is at version 5, and there is a `vitest.config.ts` at the root where the three projects are declared.

The rest of the development dependencies are the standard modern Nuxt set: `nuxt` at `^4.6.1`, `@nuxt/devtools`, the `@nuxt/eslint` packages with `eslint` at `^10.12.0`, `typescript` at `^5.9.3`, `postcss-nesting` and `@nuxthub/core` at `^0.10.8`, which is the client of the Cloudflare Pages deployment.

The `app/` and `server/` split in the repository is the same split that the test projects mirror, and a developer copying this project would be well advised to keep it that way.

## The Node version in the README is not the one the package asks for

There is a small inconsistency in this repository that a reader will hit within the first five minutes, and it is worth naming because it is the kind of thing that a template inherits and never fixes.

The build setup says that Node.js 14 or later is required. The package metadata says something quite different. There is a `devEngines` block that asks for Node `^24.21.0` and for the package manager `pnpm` at `12.11.2`, with `onFail` set to `warn` in both cases.

So the README describes a project you can run on a long-term support release of Node from years ago, while the metadata describes a project that expects a very recent release and a specific package manager, and the `devEngines` mechanism only warns rather than refusing. A developer on an old Node will get a warning, not an error, and the failure will appear later and look like something else.

There are more signs of the same drift. The lockfile in the repository is `pnpm-lock.yaml` and there is a `pnpm-workspace.yaml`, while the build instructions say `npm install`, with a comment that says or yarn. The `.node-version` file pins a version for tools that read it. And `renovate.json` is present, so the dependency versions are expected to move on their own.

None of this is a defect, it is the ordinary state of a template maintained by people who are also shipping the framework. It does mean that a team copying the setup should trust the package metadata over the prose, and should decide its package manager once rather than shipping three options in a comment.

## Where this template is the wrong tool

The limits are obvious once you notice what the application does, and they are worth stating so that nobody mistakes the demo for a product.

First, a Hacker News clone is a reading interface. There are no accounts, no submissions, no comments and no moderation, because the point of the project is to demonstrate the framework rather than to be a forum. A team that wants a discussion product cannot take this code and grow it into one, and a team that wants a Hacker News reader can usually get more from an API and a small client.

Second, the dependency versions are pinned to a moving framework. The `nuxt` dependency is at `^4.6.1` and the caret means the next minor release of the framework arrives with the next install, and Vitest, ESLint and TypeScript move with it. That is fine for a demo that is redeployed continuously, and it is a maintenance decision for a project that copies it and then wants to stay put.

Third, the performance number is one page on one connection profile. A clone of a reading interface with a small payload can reach a perfect Lighthouse score and still say nothing about an application with a large data set, a slow API or authenticated pages.

The alternative approach, for a team starting an application, is to copy the parts that are about the framework rather than the parts that are about the clone. The routing structure, the `server/` directory, the Nitro deployment setup, the Vitest project layout and the ESLint configuration are the durable parts. The Hacker News data model and its components are the disposable part, and the fastest way to use this repository well is to read it once, take the configuration, and start with an empty `app/`.

## Conclusion

The nuxt/hackernews repository fits a developer who wants one complete Nuxt application to read before writing their own, with the routing, the data layer and the deployment wired up, and with a test setup that shows how the framework's own testing utilities are meant to be used. It is the wrong choice for a production application, because a Hacker News clone is a reading interface with no accounts, no writes and no moderation, and because the dependency versions move with the framework. Before basing a project on it, check the Node version, because the README says 14 or later while the package metadata asks for a much newer release, and read the `nuxt.config.ts` and the `server/` directory, which is where the parts you would actually keep live.

## FAQ

### How do I run the Nuxt Hacker News clone locally?

Run `npm install` and then `npm run dev`, which serves the application with hot reload at localhost:3000. `npm run build` and `npm start` produce and serve the server-side rendered production version, and `npm run lintfix` validates and fixes with ESLint and Prettier.

### Which Nuxt version does nuxt/hackernews use?

The package metadata pins `nuxt` at `^4.6.1` with the Vite-based tooling, TypeScript at `^5.9.3` and Vitest at `^5.0.3`. The earlier Nuxt 2 version of the project is kept on a separate `nuxt2` branch.

### How is the nuxt/hackernews demo deployed?

On Cloudflare Pages with NuxtHub, and the deployment is the output of `npm run build`. The README also notes that the application deploys anywhere with zero config, powered by Nitro, naming Vercel, Netlify and Cloudflare among the targets.

### What tests does the Nuxt Hacker News project have?

Vitest with three projects, unit, nuxt and e2e, run through the scripts test, test:unit, test:nuxt and test:e2e. The dependencies behind them are @nuxt/test-utils, @vue/test-utils and happy-dom, with the projects declared in vitest.config.ts.

## Sources

- [Issues](https://github.com/nuxt/hackernews/issues)
- [License: MIT](https://github.com/nuxt/hackernews/blob/main/LICENSE)
- [nuxt/hackernews on GitHub](https://github.com/nuxt/hackernews)
- [Project website](https://hn.nuxt.dev)
- [README](https://github.com/nuxt/hackernews/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nuxt-hackernews
