On this page
This walkthrough takes about five minutes. It assumes you’ve installed lokal and run
lokal setup. None of the commands below need sudo or ask for a password, and each URL works as
soon as its command returns.
1. Create a project#
A project owns one domain. Create one per repo. The repo’s directory name makes a good project name.
$ lokal project create shop
✓ Created shop.lokal (current project) (done in 9ms)
Next: lokal service add api 4000The new project becomes the current project, so the service commands below use it without any extra flags.
Project names use letters, digits and -. Running project create again for a project that exists is safe: it
makes that project current again.
New projects get .lokal names. To give a project a .local domain instead, pass --domain when you create it,
for example lokal project create legacy --domain legacy.local.
.lokal or .local? explains the difference.
2. Add services#
Each service is a subdomain routed to a port on your Mac. Start your dev server, then route a name to its port:
$ lokal service add api 4000
✓ api.shop.lokal → localhost:4000 (ready in 8ms)
https://api.shop.lokal
$ curl https://api.shop.lokal # works: no -k, no --cacertIf nothing is listening on the port yet, lokal still adds the route and tells you:
$ lokal service add @ 3000 # the apex itself: https://shop.lokal
✓ shop.lokal → localhost:3000 (ready in 7ms)
https://shop.lokal
note: nothing is listening on localhost:3000 yetA few more forms:
$ lokal service add v1.api 4001 # nested names work too: https://v1.api.shop.lokal
$ lokal service add db-ui 8080 --host 127.0.0.1 # an upstream host other than localhost@routes the project’s apex,https://shop.lokal.- Nested names such as
v1.apigive youhttps://v1.api.shop.lokal. --hostsends requests to a host other thanlocalhost. You rarely need it:localhostalready works whether your server listens on127.0.0.1or only on::1. lokal warns if the host isn’t loopback.
Adding the same service again changes nothing. Adding an existing name with a different port fails and prints the
lokal service update command to use instead.
3. See what you have#
lokal list shows every project with its services and URLs:
$ lokal list
shop shop.lokal (current)
@ https://shop.lokal → localhost:3000
api https://api.shop.lokal → localhost:4000
db-ui https://db-ui.shop.lokal → 127.0.0.1:8080
v1.api https://v1.api.shop.lokal → localhost:4001lokal list --json prints the same thing in a stable, machine-readable format for scripts and coding agents.
4. Open, change and remove services#
$ lokal open api # open https://api.shop.lokal in your default browser
✓ opened https://api.shop.lokal
$ lokal service update api --port 4002
✓ api.shop.lokal → localhost:4002 (ready in 7ms)
$ lokal service remove api
✓ Removed api.shop.lokal (done in 6ms)service, project show and open use the current project. Pass -p <project> to pick another one, or switch
with lokal project use <project>.
5. Make Node, Python and curl trust lokal#
Browsers and macOS’s own tools, curl included, trust lokal as soon as setup finishes. Node, Python and some
other tools ship their own certificate bundles. lokal env prints the exports that point them at lokal’s CA:
$ lokal env
export NODE_EXTRA_CA_CERTS='/Users/you/Library/Application Support/lokal/ca/root.pem'
export SSL_CERT_FILE='/Users/you/Library/Application Support/lokal/ca/bundle.pem'
export REQUESTS_CA_BUNDLE='/Users/you/Library/Application Support/lokal/ca/bundle.pem'
export CURL_CA_BUNDLE='/Users/you/Library/Application Support/lokal/ca/bundle.pem'Load them into your shell before you start the tool:
$ eval "$(lokal env)" # zsh, bash
$ lokal env --shell fish | source # fish
$ node -e "fetch('https://api.shop.lokal').then(r => console.log(r.status))"
$ python3 -c "import urllib.request; print(urllib.request.urlopen('https://api.shop.lokal').status)"The bundle holds the macOS system roots plus lokal’s CA, so public HTTPS sites keep working. To make it permanent,
add the eval line to your shell profile. lokal env explains each variable.
Next steps#
- Projects and services: everything the
projectandservicecommands can do. - Frameworks: Vite and other dev servers that reject unknown
Hostheaders. - Coding agents: tell an agent how to use lokal in your repo.
- Command reference: every command and flag.
- Something not working? Run
lokal doctor, then see troubleshooting.