Requires PHP 8.4+. Pick the method matching your workflow.
Which method?#
| Goal | Use |
|---|---|
| New project with tests + scripts | Composer skeleton |
| Add to existing Composer project | Composer require |
| Run a single file, no setup | PHAR |
| No PHP installed (Docker only) | Docker |
| Reproducible dev shells | Nix |
| Fastest path | Getting Started |
Composer (recommended)#
New project from skeleton#
Ships with tests, build config, ready-to-use composer scripts (repl, dev, test, build, format).
composer create-project --stability dev phel-lang/cli-skeleton example-app
cd example-app
composer replAdd to an existing project#
composer require phel-lang/phel-lang
vendor/bin/phel init my-app # scaffold phel-config.php + src/
All commands then via vendor/bin/phel <cmd> (e.g. vendor/bin/phel repl).
PHP Does this replace my PHP app? ›
No. Phel lives alongside PHP. require 'vendor/autoload.php' and call compiled Phel namespaces from PHP, or call PHP from Phel. Drop into any Composer project (Laravel, Symfony, WordPress plugin) and use where Lisp fits better.
PHAR (no project setup)#
Run without Composer. Good for quick experiments, CI one-shots, trying the language.
curl -L https://phel-lang.org/phar -o phel.phar
php phel.phar --version
Every command works the same:
php phel.phar repl
php phel.phar run src/main.phel
php phel.phar test --filter foo
Make it globally available:
chmod +x phel.phar
sudo mv phel.phar /usr/local/bin/phel
phel replDocker (no PHP required)#
No PHP installed? With Docker, run Phel in one command.
Zero-setup REPL#
Paste and you're in a live Phel REPL. No files, no install:
docker run --rm -it php:8.4-cli sh -c \
"curl -sL https://phel-lang.org/phar -o /tmp/phel.phar && php /tmp/phel.phar repl"
Container downloads PHAR fresh each run. Fine for experimenting, wasteful for daily use. See Persistent phel alias for a cached setup.
Run a Phel file from your host#
Mount cwd, run any Phel script:
docker run --rm -it -v "$PWD":/app -w /app php:8.4-cli sh -c \
"curl -sL https://phel-lang.org/phar -o /tmp/phel.phar && php /tmp/phel.phar run src/main.phel"Persistent phel alias backed by Docker#
Download PHAR once, make phel feel native:
curl -L https://phel-lang.org/phar -o phel.phar
# Add to ~/.zshrc, ~/.bashrc, or run in your shell:
alias phel='docker run --rm -it -v "$PWD":/app -w /app php:8.4-cli php /app/phel.phar'
phel repl
phel run src/main.phel
phel testComposer project with no local PHP#
Use official composer image (ships PHP + Composer):
docker run --rm -it -v "$PWD":/app -w /app composer \
create-project --stability dev phel-lang/cli-skeleton example-app
cd example-app
# Start the REPL
docker run --rm -it -v "$PWD":/app -w /app -p 2345:2345 composer composer repl
Alias for daily use:
alias dcomposer='docker run --rm -it -v "$PWD":/app -w /app composer'
dcomposer composer repl
dcomposer composer test
dcomposer composer dev
-p 2345:2345exposes default nREPL port for host editor integration. Omit if not needed.
Nix#
Reproducible dev environments. Phel is in nixpkgs: see phel on search.nixos.org or the package source.
No Nix yet? Install via Determinate Systems installer or official installer.
Ad-hoc shell#
nix shell nixpkgs#phel
phel repl
Nixpkgs may lag latest. Check
nix eval nixpkgs#phel.version. For newest, use Composer or PHAR.
Project shell.nix#
Pin PHP + Composer for the team:
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
packages = with pkgs; [
php84
php84Packages.composer
];
}
Then nix-shell and use Composer as normal.
Verify install#
Run the doctor:
vendor/bin/phel doctor ; Composer
php phel.phar doctor ; PHAR
phel doctor ; Nix / global
Checks PHP extensions (json, mbstring, readline), writable cache dir, source layout. Tells you exactly what's missing.
Clojure Mental model for the toolchain ›
Mapping from lein/deps.edn:
| Clojure | Phel |
|---|---|
deps.edn / project.clj | composer.json + phel-config.php |
lein new app foo | composer create-project … cli-skeleton foo |
clj / lein repl | composer repl or phel repl |
lein test | composer test or phel test |
uberjar | phel build (compiles to PHP) |
| nREPL | phel nrepl (bencode over TCP) |
Editor integration: nREPL + LSP. See Editor Support.
Upgrading from 0.38#
composer require phel-lang/phel-lang:^0.39
./vendor/bin/phel cache:clear # or: rm -rf .phel/cache
Cached PHP from earlier installs references renamed core types and fails to load otherwise. Rebuild downstream projects after upgrade.
Breaking changes in 0.39 (Clojure-aligned core type renames):
Variable→AtomUuid→UUIDBigInteger→BigIntRational→RatioPhelFuture→FutureExInfoException→ExceptionInfoLazyCons→Cons- Auto-refer: common
Phel\Lang\*types resolve without(:use ...).Interfacesuffix dropped (e.g.(php/instanceof x LazySeq)). User(:use ...)still overrides.
Earlier upgrades (0.37):
PhelConfigsetters replaced by immutablewithX()chain; oldsetX()shims emit deprecation notices. See Configuration.PhelConfig::forProject(ProjectLayout $layout = Flat, string $mainNamespace = ''): layout argument is first,Flatis the default.Phel\Printermoved toPhel\Shared\Printer. Phel sources should(:use Phel.Shared.Printer.Printer); the old path no longer resolves.- Cross-module exceptions +
CodeSnippetmoved toPhel\Shared\Exceptions/Phel\Shared\Parser\ReadModel. - Runtime state (cache, REPL history, error log) now lives under
.phel/. Override viawithPhelDir('...')or thePHEL_DIRenv var.
Next steps#
- Getting Started: first REPL session, project tour.
- Editor Support: Emacs, VS Code, IntelliJ, Vim.
- CLI Commands: every subcommand.
- Configuration:
phel-config.phpoptions.