Skip to content

Local Development

The tma dev command starts a local development environment for your Mini App. It runs your SPA and, when present, local API and bot workers.

Running tma dev in your project directory spins up the following:

ServicePortDescription
Vite dev server5173Your SPA with hot module replacement (always)
API worker8787Miniflare worker for `server/api/index.ts
Bot worker8788Miniflare worker for `bot/index.ts
Terminal window
tma dev
App http://localhost:5173
API http://localhost:5173/api (proxied, when API worker exists)
Bot http://localhost:5173/bot (proxied, when bot worker exists)
Press Ctrl+C to stop.
  1. Vite dev server starts on port 5173 with HMR for instant feedback during development.

  2. API routes: if server/api/index.ts or server/api/index.js exists, TMA.sh watches and bundles it with esbuild, then runs it in Miniflare on port 8787. The Vite dev server proxies /api/* requests to this worker.

  3. Bot handlers: if bot/index.ts or bot/index.js exists, TMA.sh watches and bundles it with esbuild, then runs it in Miniflare on port 8788. The Vite dev server proxies /bot/* requests to this worker.

Use tma bot register to register production, preview, or development bots:

Terminal window
tma bot register

tma dev itself runs fully local workers and does not mutate your remote bot configuration.

KV data written during local development is persisted to disk under .tma/ in your project directory, so state survives restarts of tma dev.

my-app/
.tma/
kv-data/ # Local API worker KV persistence
bot-kv-data/ # Local bot worker KV persistence (if bot worker runs)
project.json # Project configuration
server/
api/
index.ts
src/
...

To reset local state, delete .tma/kv-data/ and/or .tma/bot-kv-data/.

tma dev does not automatically pull dashboard secrets into local Miniflare bindings.

For frontend code, Vite’s normal .env loading still applies. For local worker bindings, provide local values explicitly in your code or test helpers.

See Environment Variables for more details.

API route logs are printed to the same terminal as the dev server. Use console.log in your API handlers during development:

app.get('/api/debug', async (c) => {
const data = await c.env.KV.get('key', 'json');
console.log('KV data:', data);
return c.json(data);
});

Miniflare prints logs alongside the Vite dev server output for a unified view of both client and server activity.