# Elements vs Turbopack Turbopack is an open-source incremental bundler for JavaScript and TypeScript, written in Rust and developed by Vercel for Next.js. A bundler takes the source files of a web app and turns them into the files a browser and a server load. Turbopack is [built into Next.js](https://nextjs.org/docs/app/api-reference/turbopack): since version 16 it is the default bundler for both the `next dev` development server and the `next build` production build, with webpack still available through a `--webpack` flag. It compiles TypeScript and JSX with SWC, processes CSS with Lightning CSS, runs webpack loaders, and caches its work down to the function level, saving results to disk between runs. In development it compiles only what the dev server requests. Turbopack is used through Next.js, and it is free; what Vercel sells is hosting ([Elements vs Vercel](/vs/vercel)). Elements is not a bundler, and it does not ship one to compete with Turbopack. It is an integrated app environment for building web apps, built for people and their agents. At its center is a build server: a project server that runs while you work. It holds the build graph and build state in memory, so on every save the build state is updated almost instantly. It builds in milliseconds and answers agents and humans in microseconds. Installing packages, type checking server code, browser code and templates, compiling code for the server and the browser, running tests and applying migrations are all steps of that one build, and the work a bundler does is one of those steps. The same system includes a default app framework, a bundled Postgres database, and a deploy command for any Ubuntu server you reach over SSH. Elements charges for that tooling, per machine, and meters nothing ([pricing](/pricing)). Turbopack bundles, and a Next.js project assembles the rest of its build from other parts. Type checking is `tsc`, run as its own step. Installs go to npm or pnpm. Tests need a runner you choose, migrations need a migration tool, and deploy needs a pipeline. Each is configured and connected by hand, and every handoff between them is a place the build breaks: a `tsconfig.json` that has to agree with `next.config`, a cache that serves code from before your last edit, an error that `next dev` never showed and `next build` stops on. A person loses time to those, and an agent goes in circles. Elements is ready out of the box. Installs, type checks, compiles, tests and migrations are steps of one well engineered build, run by the project server in a process of its own, with every page compiled before the first request and every error reported to you and your agent from one command. The apps it builds stay close to the metal, in HTML, CSS, TypeScript, SQL and function calls, with `app.route()`, `session.login()`, `sql()`, `@rpc` and tests as the framework vocabulary. ## At a Glance | | Elements | Turbopack | |---|---|---| | What it is | A build server that runs while you work, inside an integrated app environment | A bundler built into Next.js | | What it builds | [Elements apps](/learn/man/start): server code, browser code, templates, styles, tests and migrations | Next.js apps | | Where the build runs | [Its own process](/learn/man/build), separate from your running app | Inside the Next.js dev server, the process that also renders your pages | | Pages in development | [Compiled by the build](/learn/man/build), before any request | Compiled when you open or navigate to them | | Build errors | [One build](/learn/man/build): type errors, failing tests, migration errors and server code reachable from the browser | Turbopack reports compile errors; `tsc`, a test runner and a migration tool report the rest | | Package install | [A step of the build](/learn/man/packages) | npm, pnpm or another package manager | | Tests | [A step of the build](/learn/man/tests), each test in a Postgres transaction that rolls back | Not included | | Migrations | [A step of the build](/learn/man/migrations), applied when you save them | Not included | | Build state | [One project server](/learn/man/build) shared by your terminal, your editor and every agent | A cache in the project's `.next` folder | | Configuration | One `config.jsoc` file, and no `tsconfig.json` | A `turbopack` key in `next.config`, webpack loaders, and a `tsconfig.json` | | Deploy | [`elements deploy`](/learn/man/deploy) runs the same build on your servers, with tests and migrations | Not part of Turbopack | ## A Bundler Is One Step. Elements Is the Build. Getting a web app ready to run takes several jobs: installing its packages, checking its types, compiling it for the server and the browser, running its tests, and migrating its database. Turbopack does the compiling. Its own docs say "Type-checking is not done by Turbopack (run `tsc --watch` or rely on your IDE for type checks)" ([Turbopack](https://nextjs.org/docs/app/api-reference/turbopack)). The other jobs belong to a package manager, a test runner and a migration tool that you choose, configure and run yourself. In Elements, those jobs are [steps of one build](/learn/man/build), run by the project server. You do not run them one by one. You save a file, and the build state is updated almost instantly, because the project server already knows the build and redoes only what the change touched. Your agent asks for the result with one command: ```bash elements build -json # type errors, failing tests and migration errors, in one answer ``` The answer always reflects what is on disk. An agent that writes a file and asks in the same moment gets the result of that save, not the state from before it. ## Every Page Is Compiled Before You Open It In development, Next.js builds a page when you ask for it. `next dev` [compiles routes "as you open or navigate to them"](https://nextjs.org/docs/app/guides/local-development), and Turbopack "only bundles what is actually requested by the dev server" ([Turbopack](https://nextjs.org/docs/app/api-reference/turbopack)). A page waits on its compile the first time it is requested, unless an earlier session left it in Turbopack's disk cache. A page nobody has opened has not been compiled, so its compile errors wait until someone opens it or runs `next build`. Elements compiles every page as part of the build. The build walks the import graph from your app's entry points and compiles every file your app can reach, then releases it ([build](/learn/man/build)). `elements build` does this without starting your app at all. A page is ready before anyone requests it, and an error in a page nobody has opened is in the build's answer like any other error. ## Your Compiler Should Not Take Your App Down With It `next dev` runs Turbopack inside the Next.js dev server, the same process that renders your pages. Whatever the compiler holds, your app's process holds too. The Turbopack issue "[Turbopack dev server uses too much RAM and CPU](https://github.com/vercel/next.js/issues/81161)", with 100 reactions on GitHub, reported each route compile adding memory to the dev server process. It was closed as completed in August 2026, and dev server memory growth is still reported in open issues: "[Turbopack dev: a route handler compiled after N pages costs ~16 MB × N (50 pages + 34 handlers → 29 GB); regressed in 16.3.0-canary.101](https://github.com/vercel/next.js/issues/98707)" and "[Dev server retains ~90 MB per edit of a Server Component and consumes memory without bounds](https://github.com/vercel/next.js/issues/98221)". When the dev server's memory runs high, Next.js restarts it, printing "[⚠ Server is approaching the used memory threshold, restarting...](https://github.com/vercel/next.js/issues/83275)". Because the compiler and your pages share that process, the restart takes the running app down with the compiler. Elements keeps them apart, by design. The project server is its own program, and your app runs in a separate Node process ([build](/learn/man/build)). Your app is hot reloaded in place on save, and never restarted. If it crashes, `elements start` exits with its exit code, and the project server keeps running with the build state intact, so `elements build -json` still answers. What the compiler holds in memory is never your app's memory. ## Turbopack Reports Only Its Own Errors A build finds mistakes of several kinds: type errors, failing tests, migrations that no longer apply, and code that crosses the server boundary. Turbopack reports compile errors and leaves the rest to other tools. Next.js checks types at `next build`, by running the project's `tsc` as its own step, one that `typescript.ignoreBuildErrors` switches off ([Next.js TypeScript](https://nextjs.org/docs/app/api-reference/config/typescript)). The type checker and the bundler each read the project for themselves. In Elements, every build error comes from one build: type errors, failing tests, migration errors and program analysis, such as server code reachable from the browser, found in milliseconds and reported in microseconds. [Type checking](/learn/man/typescript), [tests](/learn/man/tests) and [migrations](/learn/man/migrations) run against the same graph in memory that the build compiles, and a save redoes only the work that depends on what changed. Templates are checked like `.ts` files, and calling server-only code such as `sql()` from code the browser can reach is a compile error at the call site. Any build error stops the release. ## A Cache Folder Is Not a Build State Turbopack keeps its cache in the project's `.next` folder, one for `next dev` and one for `next build`, and the build cache only helps when that folder is restored before each build ([filesystem cache](https://nextjs.org/docs/app/api-reference/config/next-config-js/turbopackFileSystemCache)). Open reports describe that cache and the hot reloader serving an earlier version of the code: "[Tailwind v4 persistent cache stuck on CSS syntax errors in Next.js (Turbopack & Monorepo)](https://github.com/vercel/next.js/issues/90563)", "[Turbopack: SWC plugin(s) runs with another configuration after persistent cache restore](https://github.com/vercel/next.js/issues/99163)", "[Turbopack: CSS HMR sometimes lags one revision behind edits](https://github.com/vercel/next.js/issues/93052)" and "[Turbopack: HMR stops updating after client navigation](https://github.com/vercel/next.js/issues/98699)". The Elements project server holds the build graph and build state in memory, and every client reads the same state: your terminal, your editor and every agent working in parallel ([build](/learn/man/build)). Saves, installs and test runs pass through one build loop in order, so no two clients step on each other's work. Every source has a version derived from its content and everything it depends on, and a change recomputes that file and its dependents. ## Nothing to Configure or Port Turbopack is set up under a `turbopack` key in `next.config`, alongside a `tsconfig.json`. It runs webpack loaders but ["does not support webpack plugins"](https://nextjs.org/docs/app/api-reference/turbopack), does not read a `webpack()` config, and does not support custom Sass functions or Yarn Plug'n'Play. A project moving from webpack ports its config and replaces its plugins. The seam between the bundler and the package manager breaks too. The most-reacted open issue labelled Turbopack, with 43 reactions, open since December 2025, is "[Turbopack generates external module references with hashes that don't match installed packages when node_modules structure differs](https://github.com/vercel/next.js/issues/87737)", and another is "[Turbopack fails to resolve next/package.json with pnpm v11 enableGlobalVirtualStore](https://github.com/vercel/next.js/issues/93556)". An Elements project has one [`config.jsoc`](/learn/man/config) file and no `tsconfig.json`. Templates, styles, assets and environment variables are handled by the build itself, so there is no loader or plugin chain to assemble or port. Package installs are a step of the same build, so the installer and the compiler read one source graph. A missing or mistyped environment variable fails the build instead of the running app. ## Turbopack Comes With Next.js Attached Turbopack is used through Next.js. Vercel wrote in 2024 that it still wants standalone use, but that "our immediate focus is on Next.js to start" ([Vercel](https://vercel.com/blog/turbopack-moving-homes)). Choosing Turbopack means choosing Next.js and React, and then picking a database, sign-in, a test runner, a migration tool and a deploy pipeline, and connecting each one yourself. Elements does not build Next.js apps. That is a choice: its default framework was engineered with the build, so it is ready the first time you run it. Pages are written in [Elements HTML](/learn/man/html), standard HTML with typed reactive expressions, rendered on the server and updated in the browser. Routes, [`@rpc`](/learn/man/rpc) server functions, sessions, realtime data, background jobs and email ship in the same framework and are checked by the same build. Elements is not React compatible. React's packages and webpack's loaders are a shortcut for an agent only where they do something it cannot write quickly from standards, and for building a page that surface is small: an agent would rather write HTML and CSS directly than learn a UI library, and every loader in the chain is one more config to keep in agreement. That does not make frameworks useless. An agent should not write machine code, or install a package to subtract two numbers, and between those ends sits the plumbing: routing, typed server calls, sessions and a database driver, the things every app needs, which the Elements app framework ships as `app.route()`, `@rpc`, `session.login()` and `sql()`. Past that plumbing there is a point of diminishing returns, where each further abstraction or loader costs an agent more to learn and get right than it saves. The value there is in correction: finding out what it got wrong the moment it gets it wrong. Elements keeps the rest to HTML, CSS, SQL and TypeScript function calls, and puts its engineering into the build: one coherent system checks every page, function, query, test and migration, and server code has no `await` for an agent to forget. [Elements vs Next.js](/vs/nextjs) compares the default framework with Next.js. ## Who Pays for Turbopack Turbopack is a venture-subsidized open-source bundler, and part of the on-ramp to Vercel's metered hosting business: it builds the Next.js apps Vercel hosts. Vercel is a venture-backed company ([Vercel](https://vercel.com/blog/series-f)), and it charges a fee per seat plus metered compute, requests and data transfer ([Vercel pricing](https://vercel.com/pricing)). Turbopack exists for Next.js, whose research and development "is led by the core team working full-time at Vercel" ([governance](https://nextjs.org/governance)), so the hosting company sets the bundler's direction. Elements is a company that sells its tooling directly, per machine, with nothing metered ([pricing](/pricing)), so what it earns from is the tooling itself. The build server is what it charges for; the app framework and runtime packages such as `@elements/app` are MIT licensed, and everything you build is yours ([licenses](/learn/man/licenses)). ## Deploy Is the Same Build, on Your Server Turbopack's work ends when it writes the build output. Getting that output onto a server, with tests run and the database migrated, is a pipeline you assemble. The production build has memory reports of its own, still open: "[Turbopack build saturates 4 GB and stalls or OOMs](https://github.com/vercel/next.js/issues/97802)". `elements deploy` runs the same build system on your server ([deploy](/learn/man/deploy)). The project server on your machine talks directly to the one on your deploy machine, so only changed files transfer. The first deploy to a new machine takes a few seconds, and later deploys often finish in under a second. Tests run on every machine, and migrations run once, on the first machine. If any step fails, the deploy stops and the running release keeps serving ([what deploy does](/learn/man/deploy/what-happens)). Elements also sets up the load balancer, TLS certificates and Postgres on the server. That Postgres is a good fit for prototypes and single-server apps; for several servers, or managed backups and scaling, Elements recommends a hosted Postgres, connected by setting `DB_HOST` ([setup](/learn/man/deploy/setup)). ## Questions ### What is the difference between Elements and Turbopack? Turbopack is the bundler built into Next.js: it compiles a Next.js app for the browser and the server. Elements is a build server that runs while you work. Installing packages, type checking, compiling, running tests and applying migrations are steps of its one build, and the same system deploys the result to your servers. ### Is Elements an alternative to Turbopack? Elements replaces Turbopack and the tools around it. It does not ship a standalone bundler; compiling for the server and the browser is one step of its build, alongside package installs, type checking, tests and migrations. ### Does Turbopack report type errors and failing tests? No. Turbopack's docs say type checking is not done by Turbopack, and recommend running tsc --watch or relying on your editor. next build runs tsc as a separate step, and tests need a runner of your own. In Elements, every build error comes from one build: type errors, failing tests, migration errors and server code reachable from the browser. ### Can I use Turbopack without Next.js? Not as a standalone release. Turbopack is used through Next.js, and Vercel has said its focus is on Next.js before standalone use. ### Can I build a Next.js app with Elements? No. A Next.js app is built by next build, with Turbopack or webpack. Elements builds apps written with its default framework, which ships routing, server functions, sessions, realtime data, jobs, email and a bundled Postgres database. ### Does Elements compile pages when they are first requested? No. The Elements build compiles every file your app can reach before the app serves a request, and elements build reports errors in every page, including pages nobody has opened.