# Local development (/docs/composer/local-development)
> For the complete Prisma documentation index, see [llms.txt](https://www.prisma.io/docs/llms.txt). A markdown version of any docs page is available by appending `.md` to its URL.
Run the whole app on your machine with prisma dev, with no cloud credentials, and tail its logs through the control API.
Location: Composer > Local development
One command brings your whole app up on your machine, every service, its databases and buckets, wired together, with no cloud credentials. `dev` runs the same pipeline a deploy runs, but against local stand-ins for Prisma Compute and Prisma Postgres, so what you run locally is what you ship. Logs are read separately, through the control API's `log` operation.
| You want to... | Run |
| -------------------------------------- | --------------------------------------- |
| Bring the app up locally | `npx prisma dev module.ts` |
| Find where a service answers | `npx prisma dev url
` |
| Run the app in the background | `npx prisma dev module.ts --detach` |
| Stop the app | `Ctrl-C`, or `npx prisma dev stop` |
| Start clean (wipe local data first) | `npx prisma dev module.ts --fresh` |
| See everything running on this machine | `npx prisma emulator list` |
| Watch the app's logs | the `log` operation (see [Logs](#logs)) |
`module.ts` is your entry file, the one whose default export is the root module, the same file you pass to `deploy`. No `PRISMA_*` variables are needed. Local dev never talks to the platform.
`prisma dev url`, `prisma dev stop`, `--detach`, and `prisma emulator list` are in `prisma` since `8.0.0-rc.24`. Check your version with `npx prisma --version`.
## Bring it up [#bring-it-up]
Like deploy, `dev` runs your *built* output, so build first:
#### bun
```bash
bun run build
bunx prisma dev module.ts
```
#### pnpm
```bash
pnpm run build
pnpm prisma dev module.ts
```
#### yarn
```bash
yarn build
yarn prisma dev module.ts
```
#### npm
```bash
npm run build
npx prisma dev module.ts
```
It stands the app up and prints each service's local URL:
```text no-copy
dev: ready
gateway: http://localhost:3001
quotes: http://localhost:3000
```
`dev` prints `ready` only once every service accepts connections on its port, so a request to a printed URL right away connects. If a service exits before it listens, or does not listen within 30 seconds, `dev` fails instead, stops the app's other services, and names the service, its port, and its log file.
From here `dev` keeps running: it watches your built output and, when a service's build changes, restarts only that service. Rebuild in another terminal and the affected service picks up the change.
`dev` does not print service logs. With several services running, streaming them all inline would bury the URL list and the restart notices, so logs are read separately.
## Ports [#ports]
On a fresh start, each service gets the lowest free port from 3000 up. A service gets its port before the services that call it, so in the example above `quotes` gets 3000 and `gateway`, which calls it, gets 3001. A port that another program already uses is skipped.
A service or database keeps its port from one `dev` to the next in the same directory, even while it is stopped. If another directory has taken that port in the meantime, the instance gets the lowest free one, and `dev` prints one line naming it:
```text no-copy
[dev] service "gateway" now uses port 3004: its previous port 3001 is in use
```
Because ports differ from one machine and one directory to the next, do not hard-code `localhost:3001` in scripts or notes. Ask `dev url` instead.
## Find a running service [#find-a-running-service]
From another terminal in the same directory, ask where a service of the running app answers, by its address:
#### bun
```bash
bunx prisma dev url gateway
```
#### pnpm
```bash
pnpm prisma dev url gateway
```
#### yarn
```bash
yarn prisma dev url gateway
```
#### npm
```bash
npx prisma dev url gateway
```
```text no-copy
✔ The service gateway is running at http://localhost:3001
```
The address is the name `dev` printed next to the URL at startup. `dev url` also works for the app's databases and buckets: a database or bucket inside a module has a dotted address, such as `catalog.database`. For a database, `dev url` prints its connection string with the local credentials, and for a bucket, its S3 endpoint followed by `/`.
When its output is captured by `$(...)` or piped, `dev url` writes the URL alone, so a script can use it directly. Check the exit status first, so a failure does not run `curl` with an empty URL:
```bash
url=$(npx prisma dev url gateway) && curl "$url"
```
`dev url` prints a URL only for a node that is running. When the app is stopped, or `prisma dev` never ran in this directory, it fails with an error code a script can check; the [`dev url` reference](https://www.prisma.io/docs/cli/dev#dev-url) lists them.
## Run it in the background [#run-it-in-the-background]
`--detach` brings the app up as `dev` does, prints the same URLs, and then exits with code `0`, leaving the app running. Use it in scripts, CI, and coding agents, which then have no long-running process to manage:
#### bun
```bash
bun run build
bunx prisma dev module.ts --detach
curl "$(npx prisma dev url gateway)"
bunx prisma dev stop
```
#### pnpm
```bash
pnpm run build
pnpm prisma dev module.ts --detach
curl "$(npx prisma dev url gateway)"
pnpm prisma dev stop
```
#### yarn
```bash
yarn build
yarn prisma dev module.ts --detach
curl "$(npx prisma dev url gateway)"
yarn prisma dev stop
```
#### npm
```bash
npm run build
npx prisma dev module.ts --detach
curl "$(npx prisma dev url gateway)"
npx prisma dev stop
```
A detached app does not pick up rebuilds. To apply a new build, run `prisma dev module.ts --detach` again, or run `prisma dev module.ts` in the foreground: it applies the current build to the running app, then watches for rebuilds as usual, and `Ctrl-C` stops the app.
If a detached start fails before every service answers, `dev` stops the whole app and exits non-zero. That includes an app an earlier `--detach` left running, because the failed start has already replaced some of its services. Fix the build and run `prisma dev module.ts --detach` again.
## Stop the app [#stop-the-app]
`Ctrl-C` stops your app's service processes and its local Postgres servers, and exits. The emulators that ran them keep running for the next start. So does `dev` ending on a failure. A detached app keeps running until you stop it:
#### bun
```bash
bunx prisma dev stop
```
#### pnpm
```bash
pnpm prisma dev stop
```
#### yarn
```bash
yarn prisma dev stop
```
#### npm
```bash
npx prisma dev stop
```
`dev stop` stops the app that `prisma dev` last ran from this directory and lists what it stopped. When nothing of the app was running, it prints `Nothing of my-app was running.` and still succeeds, with `my-app` replaced by your app's name. Use it too when `prisma dev` was killed without a chance to stop the app.
Stopping keeps the data and the ports, so the next `dev` is a warm start: same ports, same data.
## Each directory runs its own app [#each-directory-runs-its-own-app]
The services, databases, and buckets `dev` runs belong to the directory you run it in. Two checkouts of the same app, such as two clones of its repository, run separate service processes on separate ports, with separate databases and separate buckets. A rebuild in one never restarts the other's services, and a row or an object written in one is not visible in the other.
A directory keeps the local state of every app you run from it. If you run a different app from the same directory (another entry file, or the same one under another name with `--name`), `dev` first stops the previous app's services and databases, keeps their data and ports, and says so:
```text no-copy
[dev] stopped the local services of "shop", the app run here before; its data is kept
```
Running `shop` again with `prisma dev` resumes it.
A stopped service or database keeps its port reserved, and a database keeps its data, even after you delete the checkout. There is no command to remove them yet.
## Start clean with `--fresh` [#start-clean-with---fresh]
`--fresh` deletes this app's local services, databases, and buckets, with their data, before starting. The next start creates them again, empty, and gives the services the lowest free ports. Other apps run from the same directory keep theirs. Use it when your local data is disposable, which during development it usually is:
#### bun
```bash
bunx prisma dev module.ts --fresh
```
#### pnpm
```bash
pnpm prisma dev module.ts --fresh
```
#### yarn
```bash
yarn prisma dev module.ts --fresh
```
#### npm
```bash
npx prisma dev module.ts --fresh
```
Run with `--fresh` too if `dev` fails after you upgrade Composer with an error such as `No provider is registered for resource type 'PrismaComposer.Database'`. Local state from an older Composer version is not converted for the new one.
## See everything on this machine [#see-everything-on-this-machine]
An emulator is the program on your machine that stands in for Prisma Compute, Prisma Postgres, or a bucket, and holds one instance for each service, database, or bucket that `dev` started. The emulators are shared by every directory on the machine. `emulator list` shows each emulator, whether it is running, and every instance it holds, with the address and directory it belongs to. It works from any directory:
#### bun
```bash
bunx prisma emulator list
```
#### pnpm
```bash
pnpm prisma emulator list
```
#### yarn
```bash
yarn prisma emulator list
```
#### npm
```bash
npx prisma emulator list
```
See the [`emulator` reference](https://www.prisma.io/docs/cli/emulator) for the output and its piped form.
## Logs [#logs]
The unified CLI has no `log` command. Tail the merged logs of the already-running app with the `log` operation from `@prisma/composer/control`, the same in-process API that backs `deploy` and `dev` (see [the control API](https://www.prisma.io/docs/cli/deploy#the-control-api)):
```ts title="logs.ts"
import { fileURLToPath } from 'node:url';
import { log } from '@prisma/composer/control';
import prismaConfig from './prisma.config.ts';
const result = await log({
entry: 'module.ts',
config: {
value: prismaConfig.composer,
file: fileURLToPath(new URL('./prisma.config.ts', import.meta.url)),
},
tail: 20,
signal: AbortSignal.timeout(60_000),
});
if (!result.ok) throw new Error(result.failure.message);
for await (const { service, line } of result.value.lines) {
console.log(`[${service}] ${line}`);
}
```
`log` reads the `composer` section of your `prisma.config.ts`, so the script imports it and passes it as `config`. Run it with `node logs.ts` from the directory you run `dev` in, while `dev` runs. `log` attaches to the running app and returns the merged stream as `lines`, an async iterable, so nothing prints until you iterate it. The `signal` ends the stream, here after a minute, so the script exits on its own; leave it out and stop with `Ctrl-C`. Each line carries the service it came from:
```text no-copy
[quotes] serving a quote
[quotes] serving a quote
```
It follows live, like `tail -f`. It only reads the running app. It never builds, provisions, starts, or stops anything, so you can start and stop it freely alongside a running `dev`.
* **One service:** pass `address`, for example `address: 'cron.runner'`, exactly as the startup output prints it.
* **How much history:** `tail` sets how many recent lines to show before going live (default `0`, live only). Each service's log is cleared when it starts fresh, so you are never scrolling back through past sessions.
* **No running app:** if you have not run `dev` (or you stopped it), `log` succeeds with an empty `services` list and a stream that has already ended, so the script prints nothing and exits.
## What's local vs. what's real [#whats-local-vs-whats-real]
Everything above the cloud boundary is real: your actual service code, real databases you can migrate and query, real object storage, and the same wiring a deploy creates, including [service keys](https://www.prisma.io/docs/composer/services-and-contracts#calls-are-authenticated-for-you). What is swapped are the providers underneath: local emulators stand in for Prisma Compute and Prisma Postgres, so no token, workspace, or network is involved. Three consequences worth knowing:
* **Direct RPC probes get `401` here too.** `dev` runs the deploy pipeline, so providers only accept their wired consumers, exactly as in production. Exercise a provider through a consumer, or in [tests](https://www.prisma.io/docs/composer/testing), where nothing is provisioned and every call passes through.
* **Unset secrets do not stop the app.** A secret you have not set in your shell gets a local placeholder and a one-line warning. The app boots and serves. Only the code path that actually uses that secret fails, at the real external service it calls. Set the secret in your shell to exercise that path.
* **The emulators outlive a session.** They are shared, machine-wide programs, so your data survives `Ctrl-C` and even a reboot until you pass `--fresh`. That is what makes restarts warm.
Windows is not supported yet; see [Limitations](https://www.prisma.io/docs/composer/limitations).
## Next steps [#next-steps]
* [Deploying](https://www.prisma.io/docs/composer/deploying): the same app, on Prisma Compute.
* [Testing](https://www.prisma.io/docs/composer/testing): drive a service in-process instead of running the whole app.
* [Local development across the Prisma stack](https://www.prisma.io/docs/local-development): the app runtime, local Postgres, and local storage.
## Related pages
- [`Apps and Modules`](https://www.prisma.io/docs/composer/apps-and-modules): How services, resources, and Modules compose into a Prisma App, and how provision() wires them together.
- [`Building blocks`](https://www.prisma.io/docs/composer/building-blocks): Compose the ready-made cron, storage, and streams Modules instead of building scheduled jobs, blob storage, or event streams yourself.
- [`Core concepts`](https://www.prisma.io/docs/composer/core-concepts): The ideas every Composer declaration and command builds on: services, resources, Modules, ports, contracts, stages, and the deploy model.
- [`Databases`](https://www.prisma.io/docs/composer/databases): Give a service a Postgres database, either as a plain connection or typed by a Prisma ORM contract with managed migrations.
- [`Deploying`](https://www.prisma.io/docs/composer/deploying): Deploy a Prisma App to production or an isolated stage, run it in CI, and tear environments down safely.