Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Run the notes examples locally

Local testing is optional; the deployment walkthrough uses managed PaaS resources. These commands use only the disposable services in the example’s compose.yaml. The supplied passwords are local demo values, not PaaS credentials.

1. Start the services

Install Docker with Compose. From an unpacked notes download, run:

docker compose up -d --wait
cp .env.example .env
set -a
. ./.env
set +a

From a repository checkout, use docker compose -f ../../compose.yaml up -d --wait inside examples/<language>/notes instead. The file starts PostgreSQL, MariaDB, MongoDB, Redis, and a SeaweedFS S3 service. All published ports bind to 127.0.0.1. They use unusual port numbers to avoid colliding with your existing development databases.

2. Choose a primary database

The default .env.example selects PostgreSQL. For another engine, change these two values in your local .env, then load it again in both web and worker terminals:

DATABASE_ENGINEDATABASE_URL (local demo only)
postgresqlpostgresql://tutorial:tutorial@127.0.0.1:18432/notes
mariadbmysql://tutorial:tutorial@127.0.0.1:18306/notes
mongodbmongodb://tutorial:tutorial@127.0.0.1:18017/notes?authSource=admin

REDIS_URL=redis://:tutorial@127.0.0.1:18379/0 is shared by the web and worker. Run one language at a time against this local queue; otherwise one language’s worker can pick up another’s export request. Use distinct Redis database numbers for independent simultaneous examples.

3. Install and start the chosen app

Follow the download’s README to install dependencies. Initialize the schema once, then start the web process and worker in separate terminals with the same environment:

LanguageInitialize schemaWebWorker
Node.jsnode app.mjs migratenpm startnode app.mjs worker
Railsbundle exec ruby bin/rails runner 'NotesStore.migrate'bundle exec puma -b tcp://0.0.0.0:3000bundle exec ruby worker.rb
Pythonpython app.py migrategunicorn --bind 0.0.0.0:3000 app:apppython app.py worker
Gogo run . migratego run . webgo run . worker
Rustcargo run --locked --bin migratecargo run --locked --bin webcargo run --locked --bin worker

Activate .venv in each Python terminal. For Rails, set a local SECRET_KEY_BASE using ruby -rsecurerandom -e 'puts SecureRandom.hex(64)'; use RAILS_ENV=development locally. Open http://localhost:3000, save a note, and export it. Without the optional S3 variables, the worker stores the generated JSON in Redis.

4. Enable local object storage

Uncomment all five S3/AWS variables in .env and reload it. With the AWS CLI installed, create the local bucket once:

aws --endpoint-url "$S3_ENDPOINT" --region "$S3_REGION" s3 mb "s3://$S3_BUCKET"

Restart both processes with those variables and request a new export. List its file:

aws --endpoint-url "$S3_ENDPOINT" --region "$S3_REGION" s3 ls "s3://$S3_BUCKET/exports/"

These settings point at the local S3-compatible service. On PaaS, bucket attachments supply the actual endpoint, region, name, and credentials instead.

5. Stop and reset

Stop web/worker processes with Ctrl+C. docker compose stop retains local service state; docker compose down -v removes the local tutorial containers and data. From the repo checkout, include -f ../../compose.yaml again. These commands do not touch your PaaS resources.

Return to your language tutorial for hosted deployment, or continue with production preparation.