Documentation Index
Fetch the complete documentation index at: https://docs.edgespark.dev/llms.txt
Use this file to discover all available pages before exploring further.
edgespark dev runs your full-stack EdgeSpark project on your machine. The CLI launches a local Miniflare process with both the user-worker and the platform’s sidecar bound to local D1 and R2, starts the Vite dev server for the frontend, and proxies both under one origin with hot reload.
The goal is a zero-config loop for the common case — email/password auth, database, and storage all work immediately — and a short path to OAuth and external APIs when you need them.
Start the dev server
From your project root:http://localhost:7775. Pick a different port with --port:
dev is long-running. Stop it with Ctrl+C; stop and wipe local state in one step with --reset:
What runs locally
Whenedgespark dev starts, you get:
- Local D1 — a SQLite file managed by Miniflare. The schema in
server/src/defs/db_schema.tsis pushed viadrizzle-kit pushbefore the workers start, and re-pushed after every save; destructive changes (drop column,NOT NULLwithout a default) auto-apply and may truncate tables. - Local R2 — a filesystem-backed bucket. Presigned URL uploads work through a local S3 proxy.
- Local auth — email/password ready out of the box. Sessions use a local KV namespace.
- Reverse proxy on one port —
http://localhost:7775/api/*hits the worker; every other path hits the Vite dev server. Same origin, so cookies and CORS are not a problem. - Hot reload — backend source changes trigger an esbuild rebuild and reload the worker without a process restart. Frontend uses Vite HMR.
- Dev-mode email — no email is sent. Verification URLs are stored in a dev-only row keyed by email, and
/api/_es/dev/auto-verifyreplays them through Better Auth so signup proceeds without a mailbox round-trip. To test real email delivery, deploy to a cloud environment.
Local values with .env.local
.env.local holds the values that differ between your machine and a deployed environment — OAuth client secrets, external API keys, and anything else declared in server/src/defs/runtime.ts.
The file is local to your machine, must stay gitignored, and is read at each edgespark dev start. On reload, changing .env.local is enough — the CLI re-reads values without you restarting the process.
Example:
.env.local
server/src/defs/runtime.ts (VarKey / SecretKey unions) or referenced by configs/auth-config.yaml are loaded into the local worker — undeclared lines in .env.local are silently ignored. Add the key to runtime.ts first.
Keys you declare in server/src/defs/runtime.ts but leave unset in .env.local show a startup warning and become null or undefined at runtime:
configs/auth-config.yaml that reference a missing secret remain unavailable locally — the rest of the app boots normally.
Dev-mode email and auto-verify
Inedgespark dev, no email leaves your machine — the local sidecar always intercepts Better Auth’s email hooks regardless of any *_API_KEY you set. Each verification URL Better Auth generates is written to a dev-owned row keyed by email, and the dev-only endpoint /api/_es/dev/auto-verify replays it through the auth handler to issue a session.
You normally do not call this endpoint by hand. ctx.auth.createUser (see seed data) already calls it for you, and your app’s signup flow can follow the same pattern in dev. The fact a URL was issued is logged so you can spot-check it:
.env.local switch that turns the dev override off.
Hot reload behavior
| Change | Effect |
|---|---|
Backend source in server/src/ | esbuild rebuilds the bundle; Miniflare reloads the worker in place |
Frontend source in web/src/ | Vite HMR updates the browser without a full reload |
.env.local | Worker reloads with updated bindings |
configs/auth-config.yaml | Worker reloads with the new auth config |
server/src/defs/db_schema.ts | Re-pushed via drizzle-kit push after every successful rebuild — saving the file is enough. Destructive changes auto-apply locally. |
NOT NULL without a default — auto-apply locally and may truncate tables. Use seed data so you can rebuild a known state on demand.
Database and storage in dev
Bothclient.db and client.storage work against local bindings with no code changes:
- Schema sync — the CLI runs
drizzle-kit pushagainst local D1 before the workers accept traffic, and again after every backend rebuild, applyingserver/src/defs/db_schema.tsdirectly. No migration files are needed locally — the production deploy still runsedgespark db migrate. - D1 queries — identical API to production; SQL validation runs in the sidecar the same way.
- R2 uploads and downloads — stored under
.edgespark/state/r2/. - Presigned URLs — the sidecar signs URLs against a local S3 proxy. Uploading to a presigned URL writes to the local bucket.
Seed data with server/dev/seed.ts
Templates scaffolded by edgespark init include @edgespark/devkit in server/package.json. Create server/dev/seed.ts to populate your local database on every dev start:
server/dev/seed.ts
ctx the CLI passes in gives you:
| Field | What it is |
|---|---|
ctx.db | A Drizzle client bound to the local D1 database. Type it with your own schema for full inference. |
ctx.origin | The dev proxy origin, e.g. http://localhost:7775. |
ctx.fetch(input, init?) | fetch that resolves relative paths against ctx.origin. Absolute URLs pass through. Unauthenticated — use the fetch returned from ctx.auth.createUser for authenticated requests. |
ctx.auth.createUser({ email, password, name }) | Signs up a user through the real Better Auth endpoint, then auto-verifies them via the dev-only endpoint. Returns { user, fetch } where fetch replays the user’s session cookie on same-origin requests. If the project has email verification disabled, the auto-verify call returns 404 and the seed proceeds with the session cookie from sign-up — this is fine, not an error. |
edgespark dev if the file has changed or you pass --reset; edits during an already-running session take effect on the next start.
The change-detection sentinel is a SHA-256 of server/dev/seed.ts itself — it does not cover any helper modules seed.ts imports. If you split seed logic across files and edit only a helper, touch seed.ts (or pass --reset) to force a re-run.
dev/seed.ts runs only in edgespark dev. It is never bundled into a deployed build. Use it for reproducible local state, not for production data loading.Local state and logs
Local persistence lives under your project:--reset deletes the entire .edgespark/state/ directory before starting. Use it whenever you want to rerun migrations and seed data against an empty database.
Tail .edgespark/logs/dev.log in a second terminal if you want a persistent log alongside the console output. Both .edgespark/ and .env.local must stay gitignored.
OAuth providers locally
To test a real OAuth sign-in against local dev, register a second OAuth app (or add a second callback URL on your existing one):.env.local using the exact key names from add social login (GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET, etc.). Save the file — the worker auto-reloads with the new bindings. No platform-side edgespark var set or edgespark secret set is needed for local use; those commands target deployed environments.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Port 7775 already in use | Another edgespark dev or process is on the port | Run edgespark dev --port <n> or stop the other process. |
| No verification email reaches inbox | Local dev never sends real email — the auto-verify endpoint replays the URL through Better Auth instead | Use ctx.auth.createUser in dev/seed.ts, or POST to /api/_es/dev/auto-verify?email=<email> from your client-side flow. To test real email delivery, deploy to a cloud environment. |
edgespark dev startup is stuck at “Running server/dev/seed.ts…” | A request inside seed.ts is hanging | ctx.fetch and ctx.auth.createUser time out after 30 seconds and surface the error. Check the seed for a call to an unreachable external service. |
| Stale data after schema changes | Local destructive changes auto-applied and may have truncated tables | Run edgespark dev --reset and let your dev/seed.ts rebuild state. |
| Provider button missing in local login UI | .env.local is missing a *_CLIENT_SECRET, or the provider is disabled in configs/auth-config.yaml | Add the secret, confirm the provider block has enabled: true. Saving either file auto-reloads the worker. |
| Backend changes not picked up | esbuild rebuild error, or (in fullstack mode) a backend route is declared outside /api/* | Read the error in the dev output; fix the build error or move the route under /api/*, then save again. Typecheck failures only print warnings — they never block reload. |
See also
Development workflow
The edit → CLI → deploy loop for schema, storage, vars, secrets, and types.
Add social login
Register OAuth apps and wire providers for both local
dev and deployed environments.