Setting Up Your Development Environment
Viewing:
Development mode (moose dev
) provides a full-featured local environment optimized for rapid iteration and debugging. It automatically manages Docker containers, provides hot reload capabilities, and includes enhanced debugging features.
Getting Started
# Start development environment
moose dev
# View your running infrastructure
moose ls
Container Management
Development mode automatically manages Docker containers for your infrastructure:
- ClickHouse (when
olap
feature is enabled) - Redpanda (when
streaming_engine
feature is enabled) - Temporal (when
workflows
feature is enabled) - Redis (always enabled)
Container Configuration
Control which containers start with feature flags:
# moose.config.toml
[features]
olap = true # Enables ClickHouse
streaming_engine = true # Enables Redpanda
workflows = false # Controls Temporal startup
Hot Reloading Development
The development runtime includes a file watcher that provides near-instantaneous feedback when you save code changes.
Watched Files
The file watcher recursively monitors your entire app/
directory structure and only rebuilds the components that actually changed.
- index.ts
- moose.config.toml
- main.py
- moose.config.toml
Only Runs Your Root File
Only the root file in your app/
directory is run when changes are detected. In order for your tables/streams/apis/workflows to be detected, you must export them from your root file (app/index.ts
). If you change a file in your app directory and it is a dependency of your root file, then those changes WILL be detected.
Only the root file in your app/
directory is run when changes are detected. In order for your tables/streams/apis/workflows to be detected, you must import them in your root file (main.py
). If you change a file in your app directory and it is a dependency of your root file, then those changes WILL be detected.
Quick Example
❌ Doesn’t work - No export from root:
import { UserSchema } from './schemas/user';
const usersTable = new OlapTable<UserSchema>("Users");
// Moose can't see this - not exported from root
✅ Works - Export from root file:
import { UserSchema } from './schemas/user';
export const usersTable = new OlapTable<UserSchema>("Users");
export * from './tables/users'; // Moose sees this
Now because we exported the table from the root file, Moose will detect the change and rebuild the table.
❌ Doesn’t work - No export from root:
from schemas.user import UserSchema
users_table = OlapTable[UserSchema]("Users")
# Moose can't see this - not imported in main.py
✅ Works - Import in main file:
from schemas.user import UserSchema
users_table = OlapTable[UserSchema]("Users") # No export needed - Python modules are automatically discovered
from tables.users import users_table # Moose sees this
Now because we imported the table in the main file, Moose will detect the change and rebuild the table.
✅ Works - Change dependency:
export interface UserSchema {
id: string;
name: string;
email: string;
age: number; // Adding this triggers migration
}
Moose detects this because UserSchema
is imported in the root file via the dependency chain.
Script Execution Hooks
You can configure your dev server to run your own shell commands automatically during development. Use these hooks to keep generated artifacts in sync (e.g., refreshing external models, regenerating OpenAPI SDKs).
Available hooks
on_first_start_script
: runs once when the dev server first starts in this processon_reload_complete_script
: runs after each dev server reload when code/infra changes have been fully applied
Configure these in moose.config.toml
under the http_server_config
section:
# moose.config.toml
[http_server_config]
# One-time on first start
on_first_start_script = "echo 'dev started'"
# After every code/infra reload completes
on_reload_complete_script = "echo 'reload complete'"
Notes:
- Scripts run from your project root using your
$SHELL
(falls back to/bin/sh
). - Use
&&
to chain multiple commands or point to a custom script. - Prefer passing credentials via environment variables or your secret manager.
Use case: keep external models in sync (DB Pull)
Refresh EXTERNALLY_MANAGED
table models from a remote ClickHouse on dev start so your local code matches the live schema.
export REMOTE_CLICKHOUSE_URL="https://username:password@host:8443/?database=default"
# moose.config.toml
[http_server_config]
on_first_start_script = "moose db pull --connection-string $REMOTE_CLICKHOUSE_URL"
See the full guide: /moose/olap/db-pull
Use case: regenerate OpenAPI SDKs on reload
Automatically regenerate client SDKs after Moose finishes applying code/infra changes so .moose/openapi.yaml
is fresh.
# moose.config.toml
[http_server_config]
on_first_start_script = "command -v openapi-generator-cli >/dev/null 2>&1 || npm i -g @openapitools/openapi-generator-cli"
on_reload_complete_script = "openapi-generator-cli generate -i .moose/openapi.yaml -g typescript-fetch -o ./generated/ts"
More examples: /moose/apis/openapi-sdk
Local Infrastructure
Port Allocation
Development mode uses the following default ports:
- 4000: Main API server
- 5001: Management API (health checks, metrics, admin, OpenAPI docs)
Service URLs
Access your development services at:
# Main application
http://localhost:4000
# Management interface
http://localhost:5001/metrics
# OpenAPI documentation
http://localhost:5001/openapi.yaml
# Main application
http://localhost:4000
# Management interface
curl http://localhost:5001/metrics
# OpenAPI documentation
http://localhost:5001/openapi.yaml
Container Networking
All containers run in an isolated Docker network with automatic service discovery:
- Containers communicate using service names
- Port mapping only for external access
- Automatic DNS resolution between services
Troubleshooting
Common Issues
Container Startup Failures
# Check Docker is running
docker info
# View container logs
moose logs
Port Conflicts
# Check what's using your ports
lsof -i :4000
lsof -i :5001
# Use custom ports
export MOOSE_HTTP_PORT=4040
export MOOSE_MANAGEMENT_PORT=5010
moose dev