Skip to content
Console →
Website →
Asking an AI? Paste this URL https://keelson.dev/llms.txt

Framework notes

This page covers production startup commands and considerations for each framework. Start your web server on the port specified by the PORT environment variable. Some frameworks have database or connection constraints, so also check Supported apps and constraints.

Use a production server. Development servers can have performance issues, expose internal information in error pages, and handle in-flight requests poorly during shutdown.

Your AI agent can usually handle configuration. Refer to the section for your framework when checking startup settings or investigating deployment problems.

  • Listen on 0.0.0.0 and the port specified by PORT. Requests cannot reach a server bound to 127.0.0.1.
  • Do not install dependencies in the startup command. Dependencies are installed at build time from requirements.txt, pyproject.toml, package.json, go.mod, or other supported files.
  • Shutdown sends SIGTERM, then SIGKILL after 10 seconds. Finish in-flight requests within 10 seconds.
  • Start with one worker. If you add workers, account for available CPU, memory, and the work your app performs.
  • Disable debug mode by default. Debug pages may expose environment variables, including database authentication tokens.
  • Use KEELSON_MODE to detect Keelson. A value of keelson means the app is on the platform. Keep environment detection separate from enabling or disabling debug mode.
import os
ON_KEELSON = os.environ.get("KEELSON_MODE") == "keelson"
DEBUG = os.environ.get("DEBUG", "false").lower() == "true" # Defaults to false
command: "uvicorn main:app --host 0.0.0.0 --port $PORT"
env:
PYTHONUNBUFFERED: "1"

Do not add --reload: file watching consumes memory and can start the app twice. Keep the default of one worker.

app.run() starts a development server. Add gunicorn to requirements.txt and use it to start the app.

command: "gunicorn --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 0 --graceful-timeout 9 app:app"
env:
PYTHONUNBUFFERED: "1"

Replace app:app with your module name and app object name. --graceful-timeout 9 keeps graceful shutdown within the 10-second SIGTERM window.

Django deploys only when it connects to an external database such as PostgreSQL. Managed SQLite (libSQL) has no backend for the Django ORM, so configurations that use Managed SQLite or a SQLite file as the database are not supported.

Set db.mode: none and pass the connection details as secrets. Start with gunicorn, not runserver.

command: "gunicorn --bind 0.0.0.0:$PORT --workers 1 --threads 8 --timeout 0 --graceful-timeout 9 config.wsgi:application"
db:
mode: none
secrets:
items:
- name: DATABASE_URL

Replace config.wsgi:application with your project’s WSGI module. Keep DEBUG off by default, serve static files with whitenoise (set STATIC_ROOT and run collectstatic in the build), and keep ALLOWED_HOSTS = ["*"]. See the Deploy Spec for details.

Apps using file-based SQLite may be able to connect to Managed SQLite with sqlalchemy-libsql-native. This approach is experimental. Beyond changing the connection settings, verify that models, queries, and migrations work. Ask your AI agent to review the required changes and compatibility.

Streamlit currently does not work because it requires WebSocket. Gradio 4 and later are being evaluated.

NODE_ENV is not set automatically. Declare it in keelson.yaml. Without it, frameworks such as Express may include stack traces in responses.

env:
NODE_ENV: "production"

Keelson uses npm for builds on the platform. If your project only has pnpm-lock.yaml or yarn.lock, preflight checks stop the deployment. Generate package-lock.json and verify that installation and building succeed with npm. Static sites built locally with pnpm or Yarn can still be served. See Dependency installation.

command: "npm start" # package.json: "start": "node server.js"
  • Do not return stack traces from error handlers.
  • If you use trust proxy to determine the client IP or whether a request uses HTTPS, configure it for the actual proxy path and forwarded headers. A fixed value of 1 may not work correctly (official Express guide).
  • Declare secrets for your app’s own sessions or JWTs in secrets.

Build the app and start it with next start. next dev is not a production server.

command: "npm run start" # package.json: "start": "next start -p $PORT"
  • npm run build runs automatically during the build. Check that it produces .next/.
  • Change "start": "next dev" if present.
  • Read KEELSON_DB_URL on the server. Putting it in a NEXT_PUBLIC_* variable sends it to the browser.

Keep Prisma’s provider set to "sqlite" when connecting to Managed SQLite. Change the connection method: replace the local file connection with a Prisma Client using @prisma/adapter-libsql, KEELSON_DB_URL, and KEELSON_DB_AUTH_TOKEN (connection instructions).

Use compatible versions of @prisma/adapter-libsql and @prisma/client (6.x has been tested). Configuring the adapter does not automatically apply Prisma migrations to the remote database. Ask your AI agent to verify queries with your version and how to apply generated SQL to Managed SQLite.

Keelson builds with go build -o /workspace/app . and starts the app with ./app.

runtime: go-slim
command: "./app"
  • Builds use CGO_ENABLED=0. cgo SQLite drivers such as mattn/go-sqlite3 cannot be used. Use a pure Go libSQL client for Managed SQLite.
  • Handle shutdown explicitly with signal.NotifyContext and server.Shutdown, so in-flight requests finish within 10 seconds.
  • If you use an ORM such as GORM, check database and driver compatibility. If it cannot connect to Managed SQLite, switch to database/sql and a pure Go libSQL client.

For Vite, Next.js static exports, Astro, and similar tools, build locally and deploy the output through assets.dir. Keelson does not install dependencies or build static sites that have no command.

Static sites require type: web. Files in assets.dir are included in the upload even if the folder, such as dist/, is in .gitignore. See Configure keelson.yaml for examples.

For hybrid apps combining a static frontend and API server, also build the frontend locally before deploying.