Deployment
Deploy to production, manage environment variables, and integrate with CI.
bunx valet-dev deployThe deploy command runs codegen, pushes your schema and handlers to the server, and creates a production project if one does not exist yet. On first run it saves VALET_PROJECT_URL and VALET_DEPLOY_KEY to .env.production.
Deploy command
bunx valet-dev deployThis does three things:
- Runs codegen to generate typed client code
- Pushes your schema and handler code to the server
- Applies any schema migrations (new tables, new fields, new indexes)
If the schema has breaking changes (changing a field's validator type), the push fails with an error. Add new fields and migrate data instead of changing existing field types.
Environment files
Valet uses two environment files:
| File | Purpose |
|---|---|
.env | Development credentials (from valet-dev init) |
.env.production | Production credentials (from valet-dev deploy) |
Both files contain the same two variables:
# .env.production
VALET_PROJECT_URL=https://brave-falcon-leaps-prod.fly.valet.host
VALET_DEPLOY_KEY=your_deploy_key_hereCredential priority: environment variables > .env.production > .env
Add .env and .env.production to .gitignore. Do not commit deploy keys.
Deploy keys
A deploy key authenticates CLI commands against the control plane. Each project has its own deploy key, generated during valet-dev init or valet-dev deploy.
Deploy keys are scoped to a single project. They authorize schema pushes, handler uploads, and environment variable management. They do not grant access to read or write application data.
To rotate a deploy key, regenerate through the dashboard or contact the project admin.
Project URLs
The project URL identifies your project:
https://brave-falcon-leaps.fly.valet.hostPass this URL to ValetProvider in your app — the SDK automatically converts it to a WebSocket connection:
// App.tsx
import { ValetProvider } from './_generated/valet/react'
function App() {
return (
<ValetProvider url={process.env.VALET_PROJECT_URL!}>
<TodoApp />
</ValetProvider>
)
}Development and production projects have separate URLs and separate databases.
Managed hosting
The managed platform at fly.valet.host runs on Fly.io and handles everything for you:
- Scale-to-zero: idle projects are suspended by Fly, then archived to R2 after prolonged inactivity
- Fast provisioning: projects are created in ~800ms using a warm pool of pre-provisioned machines
- Automatic dormancy and wake: inactive projects are archived to R2 storage and restored on demand
- No infrastructure to manage
Use the managed platform unless you have specific requirements for self-hosting.
Self-hosting
Self-hosting Valet means running your own valet-server instance. You can deploy it anywhere — Fly.io, AWS, a VPS, or even locally for development. See fly.server.toml in the repository root for a Fly.io example, or use the provided Dockerfile.server.
Point the CLI at your server using --project-url:
bunx valet-dev init --project-url https://my-server.example.com --deploy-key your-keyThis writes the URL and deploy key to .env without contacting any external service. All subsequent commands (codegen, deploy, env) use this URL directly.
To deploy to production, pass the production server URL:
bunx valet-dev deploy --project-url https://my-prod-server.example.com --deploy-key prod-keyConnecting your app
Pass the project URL to ValetProvider:
// App.tsx
import { ValetProvider } from './_generated/valet/react'
function App() {
return (
<ValetProvider url={process.env.VALET_PROJECT_URL!}>
<TodoApp />
</ValetProvider>
)
}Environment variables
Use valet-dev env to manage server-side environment variables. These are available in server-execution handlers through process.env:
# Set a variable
bunx valet-dev env set GITHUB_CLIENT_ID=abc123
# Set with a separate value argument
bunx valet-dev env set GITHUB_CLIENT_SECRET secret456
# List all variables
bunx valet-dev env list
# Remove a variable
bunx valet-dev env unset GITHUB_CLIENT_SECRETServer-side environment variables are encrypted at rest and scoped to a single project. Use them for API keys, OAuth secrets, and other sensitive configuration that your server-execution handlers need.
CI integration
Use valet-dev deploy as a prebuild step in your CI pipeline. This ensures codegen runs and the schema is pushed before your app builds.
package.json prebuild script
{
"scripts": {
"prebuild": "bunx valet-dev deploy"
}
}CI environment variables
In CI environments (Vercel, EAS, GitHub Actions), set VALET_PROJECT_URL and VALET_DEPLOY_KEY as environment variables instead of relying on .env.production:
# .github/workflows/deploy.yml
env:
VALET_PROJECT_URL: ${{ secrets.VALET_PROJECT_URL }}
VALET_DEPLOY_KEY: ${{ secrets.VALET_DEPLOY_KEY }}
steps:
- run: bun install
- run: bunx valet-dev deploy
- run: bun run buildThe deploy command reads these environment variables automatically. No flags needed.
Vercel
Add VALET_PROJECT_URL and VALET_DEPLOY_KEY to your Vercel project's environment variables. Use the prebuild script in package.json -- Vercel runs it automatically before the build.
EAS (Expo Application Services)
Add the variables to your EAS secrets:
eas secret:create --name VALET_PROJECT_URL --value "https://my-app.fly.valet.host"
eas secret:create --name VALET_DEPLOY_KEY --value "your_deploy_key_here"Add the prebuild script to package.json. EAS runs it before building your app.