Changelog
User-visible changes in each Elide release. Releases are ordered newest first, with routine dependency and CI-only work omitted.
On this page
Inside Elide 1.6.3
Elide 1.6.3 expands the project toolchain with Android builds, Micronaut integration, shared test services, and Python package tools. It also adds Maven version overrides, richer build telemetry, and commands for reading Markdown and rendering configuration. This release is in development; 1.6.2 remains the latest release.
Build and run an Android app
Create a Kotlin Compose app with the Android template, then build a signed development APK. Elide also builds AAR libraries and app bundles, merges workspace resources and manifests, and supports optional code shrinking. The Compose compiler is opt-in through kotlin.features.compose; the template enables it and declares the runtime dependencies.
Install an Android SDK before starting. Elide reports missing SDK components and the commands to install them. Run the following in a new directory; the keystore task creates a development signing key once. The run task installs and launches the app on an attached device, or starts the configured emulator.
Use elide build android-debug-app to launch suspended and print the forwarded debugger address. Android testing supports configured host tests and instrumented test APKs; an instrumented test APK needs its own project. App bundles with dynamic feature modules cannot yet be minified.
mkdir hello-android
cd hello-android
elide init --template android --plain --skip-defaults -- package=com.example.hello
elide build android-keystore-app
elide build app
elide build android-run-app
Build Micronaut applications
Declare a Micronaut Core version and Elide installs the matching Java annotation and native metadata processors. Put application settings in jvm.micronaut.config to generate application.json on the classpath. Elide installs the JSON loader and rebuilds affected artifacts when configuration changes; authored resource files remain supported.
Create these two files in a new project directory. The program starts a Micronaut application context and reads the message from Pkl configuration. Run elide install, then elide run; it prints Hello from Pkl.
Use the Micronaut Core version, which can differ from the platform BOM version. This integration processes Java sources; Micronaut processing through Kotlin KSP is not yet provided. The guide extends this example with JUnit tests, coverage, JVM distributions, and native executables.
amends "elide:project.pkl"
name = "hello-micronaut"
dependencies {
micronaut {
version = "4.10.23"
modules { "runtime" }
}
}
jvm {
main = "example.Application"
micronaut {
config {
sample { message = "Hello from Pkl" }
}
}
}
package example;
import io.micronaut.context.ApplicationContext;
public final class Application {
public static void main(String[] args) {
try (var context = ApplicationContext.run()) {
System.out.println(context.getRequiredProperty("sample.message", String.class));
}
}
}
Share a service across test runners
Declare databases and other test services in testing.testcontainers. Elide starts them once for the project, waits for readiness, and gives JavaScript, TypeScript, and JUnit tests the same connection settings. Host ports are allocated dynamically, so concurrent runs need no fixed port reservations.
This example starts an HTTP service and tests its response. Save both files in a new project directory and run elide test. A Docker-compatible daemon and JDK 17 or newer are required. Java and Kotlin tests can read the same TEST_URL with System.getenv("TEST_URL").
Startup failures fail the test run. Containers are cleaned up after success, failure, or cancellation; installation and compilation alone do not start them. Container tooling stays out of application dependencies.
amends "elide:project.pkl"
name = "service-tests"
testing {
testcontainers {
containers {
["web"] {
image = "busybox:1.37"
command {
"sh"; "-c"
"mkdir -p /www; echo ready > /www/index.html; httpd -f -p 8080 -h /www"
}
ports { 8080 }
wait { strategy = "http"; port = 8080 }
}
}
environment {
["TEST_URL"] = "http://${web.host}:${web.port.8080}/"
}
}
}
import test from "node:test";
import assert from "node:assert/strict";
test("service is ready", async () => {
const url = process.env.TEST_URL;
assert.ok(url, "TEST_URL must be supplied by the test runner");
const response = await fetch(url);
assert.equal(response.status, 200);
assert.equal((await response.text()).trim(), "ready");
});
Install Python packages and run console tools
Python package tooling is available on demand with the optional Python component. elide uv install adds packages to the project environment, which Elide loads without activation. elide uv tool run uses a separate environment for a console tool, keeping its dependencies out of the project.
Create the manifest below in a new directory, then install a package and run a tool. The HTTPie command prints help; it does not send a request. Tool environments are cached between runs; elide uv tool list shows them and elide uv tool prune removes expired or excess entries.
Python remains experimental. Package installation supports compatible wheels only; source builds and arbitrary CPython native extensions are not supported. elide uv exposes the documented package and tool commands, not the full upstream command set. Python tests still run through elide python -m unittest or an installed pytest, rather than elide test.
[project]
name = "python-demo"
version = "0.1.0"
requires-python = ">=3.13"
elide setup python
elide uv install attrs
elide python -c 'import attrs; print(attrs.__version__)'
elide uv check
elide uv tool run --from 'httpie==3.2.4' http --help
elide uv tool list
Select one Maven version across the dependency graph
Use dependencies.maven.resolutions when a direct or transitive dependency needs a specific version. Each key is a group:artifact pair, and the override applies before dependency metadata is fetched, including requests for other classifiers or packaging types.
In this example, the resolution selects Commons Lang 3.20.0 even though the direct dependency requests 3.19.0. Run elide install after changing the manifest. An override does not add a missing dependency or restore an excluded one.
Values must be exact versions; ranges and wildcards are rejected. Workspace members inherit root overrides and can replace them by key. Changing or removing an override invalidates the resolved dependency graph.
amends "elide:project.pkl"
name = "version-overrides"
dependencies {
maven {
packages { "org.apache.commons:commons-lang3:3.19.0" }
resolutions {
["org.apache.commons:commons-lang3"] = "3.20.0"
}
}
}
Follow a build from tasks to test results
With an OTLP destination configured, build and test commands export correlated spans for tasks, execution units, and individual tests. An invocation ID ties each report together, with task outcomes and cache status attached. In your collector, find the elide.build or elide.test root span and inspect its children.
Run these commands in an existing project with an OTLP/HTTP collector listening on port 4318. Global telemetry flags go before the command. Without a configured destination, no build or test telemetry is exported; there is no separate build-report flag.
Automatic HTTP server telemetry also gains active-request and body-size measurements, and runtime instrumentation logs retain structured fields and trace context in OTLP export. Guest CPU profiles remain experimental and require separate configuration.
elide --otel-endpoint=http://localhost:4318 --otel-protocol=http/protobuf build
elide --otel-endpoint=http://localhost:4318 --otel-protocol=http/protobuf test
# Disable telemetry for one invocation, even if the project enables it.
elide --no-otel test
Generate JSON or YAML from configuration
Evaluate .pkl or .pcf files directly and render the format your application expects. No Elide project is required. Relative imports resolve from the input file, so configuration can share nearby defaults.
Save the configuration below as config.pkl. The JSON command writes service, port, and healthPath with the same values and types; the YAML command renders the same configuration in YAML. Without --format, the module controls its output, with PCF as the default.
Rendered content goes to stdout; diagnostics go to stderr. Use --out config.json to replace a file atomically after successful evaluation, or --out - to explicitly select stdout. TOML output is not supported.
service = "api"
port = 8080
healthPath = "/health"
elide --format=json config.pkl
elide --format=yaml config.pkl
# Replace a generated file only after successful evaluation.
elide --format=json --out config.json config.pkl
Read READMEs and runbooks in the terminal
Open a .md or .markdown file to read headings, lists, tables, and highlighted code blocks with terminal-width wrapping. Task lists and strikethrough are supported. No project manifest is required.
Use an existing README or runbook with the commands below. Piped output is plain, links retain their destinations, and raw HTML is shown as text. Code examples are displayed without execution.
elide README.md
elide docs/runbook.md | less
elide --no-color README.md > readme.txt
Inside Elide 1.6.2
Elide 1.6.2 brings an embedded C compiler and linker via LLVM, C-to-Java bindings, dotenv and encrypted configuration, Java ABI compilation, and dependency-aware formatting into the toolchain.
Embedded C compiler and linker via LLVM
elide cc uses embedded Clang and LLVM to compile freestanding C17, emit host object code or textual LLVM IR, and link native code in memory with LLVM ORC LLJIT. Compilation, JIT linking, symbol lookup, and invocation run in the same process.
The current frontend accepts one translation unit. For --run, the entry point is a zero-argument function returning long long; Elide prints the result and exits with status zero. Object files can be passed to a separate build or link step. The native-tools guide specifies the supported flags, output modes, and distribution requirements.
cat > answer.c <<'EOF'
long long answer(void) { return 42; }
EOF
elide cc -- -c answer.c -o answer.o
elide cc -- -S -emit-llvm answer.c -o answer.ll
elide cc -- --run answer answer.c
# 42
C headers become Java FFM bindings
elide jextract exposes the embedded OpenJDK header-binding generator. Generate Java sources as a standalone operation, or pass headers to elide javac and compile the bindings in memory alongside application sources. --emit-bindings exports the sources when an IDE or another build step needs them.
Projects can declare named binding groups under jvm.java.bindings in elide.pkl, select them per Java source set, and include generated Java in source JARs. Include directories, macros, library names, and generator options belong to the binding group. The shared library remains a runtime dependency; callers must also enable native access when executing FFM code.
elide javac \
--jextract native/api.h \
--jextract-package example.nativeapi \
--jextract-class NativeApi \
--emit-bindings generated \
-- -d out src/main/java/example/Main.java
Environment and VM properties before startup
Application commands load .env followed by .env.local from their invocation scope. Inherited variables win, including empty values; later files override earlier file defaults. --project selects project and enclosing-project scopes. Explicit repeated --env-file arguments replace automatic dotenv discovery, so deployment profiles are selected by the caller.
Java system properties are a separate domain: .properties and .properties.local use Java properties syntax, and --properties-file selects explicit files. Operator-supplied VM assignments take precedence. --no-env and --no-properties disable their domains independently. Tool commands only consume file configuration when explicitly selected or when their command contract calls for an application context.
Dotenv supports ${NAME} interpolation at parse time. Properties values and decrypted values are not interpolated. In an already-running JVM, file variables reach supported guest environment APIs and child processes through overlays; Java's own System.getenv() retains the JVM's launch environment.
elide \
--env-file .env \
--env-file .env.production \
--properties-file config/production.properties \
run Main.java
Encrypted values in dotenv and Java properties
Both configuration formats accept dotenvx-compatible encrypted: values. Elide decrypts decoded values before application or task execution, using inherited DOTENV_PRIVATE_KEY* variables or .env.keys from the selected configuration directories. Missing keys or invalid ciphertext for an effective value fail before the relevant application starts, with diagnostics that omit the value and key material.
Encryption preserves file precedence and the distinction between environment variables and JVM properties. A decrypted payload is a value: it is not parsed again as dotenv, expanded, or executed. Java properties still apply their own escaping and encoding before decryption.
.env.keys are used only for key lookup, while inherited key variables retain normal process-environment visibility.Java header jars and Kotlin ABI compilation
elide javac --abi-only emits an ABI jar directly from Java sources through Turbine. --emit-abi adds header output to a full javac invocation. Downstream compilation can consume the headers; execution uses the implementation classes. The compiler guide covers annotation-processing behavior and the distinction between source/target selection and an older JDK API surface.
Kotlin ABI-only compilation strips non-inline bodies by default while preserving inline bodies, metadata, constants, and the declarations downstream compilers need. --emit-abi can accompany a full compilation. KAPT and KSP2 are explicit processing operations with generated-source and resource outputs, which can then feed a normal compile.
# Header-only compilation
elide javac --abi-only --emit-abi build/api.jar -- src/main/java/example/Api.java
# Implementation classes plus a header jar
elide javac --emit-abi build/api.jar -- -d build/classes src/main/java/example/Api.java
Formatting with the project's dependency graph
The jfmt dialect now attributes Java sources against the project's installed dependencies or an explicit --class-path before rewriting imports. It expands wildcard imports to referenced types, removes unused imports, and then formats the selected source. The attribution and fallback behavior is documented alongside source-path and selection options.
elide format --install resolves dependencies before formatting. --lines, --offset, and --length select a region in one file, while list and diff modes support review and automation. The guide includes commands for project-wide formatting and dependency-aware import repair.
elide format --install -- --jfmt
elide javaformat -- --jfmt --class-path libs/api.jar src/main/java/example/Main.java
elide javaformat -- --jfmt --lines 10:24 src/main/java/example/Main.java
Inside Elide 1.6.0
Runtime
- Startup floor
- 1.43 ms
- JavaScript startup
- Peak single-context RPS
- 635,510 req/s
- One JS context, no HTTP pipelining
- Peak multi-context RPS
- 11,416,311 req/s
- Fresh Elide multi-context control run
- Footprint
- 370.2 MB
- Linux x64 archive
ContributionsSep 22 – Oct 15
- Pull requests
- 239
- Bugs fixed
- 138
- Enhancements
- 121
- Lines changed
- +398K −81K
Elide 1.6.0 adds built-in telemetry, workspaces, Maven publishing, and experimental OpenRewrite and WebAssembly support. Python is now optional. Startup is faster, and multi-context HTTP serving exceeds 10 million requests/sec in the published benchmark.
OpenTelemetry, built in
Use standard OpenTelemetry API in JavaScript, TypeScript, or Python. Elide functions as an SDK and OTLP exporter for traces, metrics, logs, and errors. Profiles are experimentally supported.
Runtime-level tracing, e.g. for servers, is transparent and folds into your application's own signals. Incoming trace headers preserve trace continuity, and logs correlate automatically with traces and profiles.
Set OTEL_EXPORTER_OTLP_ENDPOINT, pass --otel-endpoint, or configure opentelemetry in elide.pkl. Presets available for Sentry, Datadog, PostHog, Honeycomb, and Grafana.
// OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 elide run app.ts
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("checkout");
await tracer.startActiveSpan("charge", async (span) => {
span.setAttribute("order.id", 42);
console.log("charged order 42"); // exported as a log record in this span
span.end();
});
Python is an optional component
Install Python with elide setup python, or add --with-python to the installer (-WithPython on Windows). Homebrew and container images include Python.
Python 3.13 and its standard library run without a separate CPython install. A simple hello-world on Linux amd64 starts up in about 4.8 ms, versus CPython’s 6.0 ms.
elide setup python before using Python after an upgrade. apt and RPM packages cannot add the component; use the installer, npm, Homebrew, or a container image.Workspaces
Multi-module projects are now supported, known as 'workspaces'. List projects in the root elide.pkl, then build or test the workspace with one command. Run from a member directory to target that project, or select it from the root with e.g. elide build core.
Members share dependency downloads and build state. project("core") selects a project for dependency use; .friend() also exposes its Kotlin internal declarations. Maven versions can inherit from the root, and conflicts fail early.
// elide.pkl, at the root
amends "elide:project.pkl"
workspace {
members { "core"; "app" }
}
// app/elide.pkl
amends "elide:project.pkl"
local core = project("core")
dependencies {
maven {
packages { core }
}
}
VS Code and IntelliJ IDEA
Open an elide.pkl project in VS Code or IntelliJ IDEA. Dependencies and source sets feed code intelligence; build, run, test, and debug use the Elide CLI. Both editors show coverage results.
Faster to start, faster to serve
Programs initialize only the language(s) they use. In our benchmarks, JavaScript hello-world starts in 1.4ms, versus Bun’s 1.6ms, Deno’s 6.3ms, and Node.js’s 11ms.
Single-context serving reached 635k requests/sec, compared with Bun at 156k, Deno at 163k, and Node at 123k. Each runtime used one application context, an equivalent handler, and the same client load and CPU budget.
- Elide 1.6.01.43 ms
- Bun 1.4.21.63 ms
- Deno 2.9.76.31 ms
- Node.js 24.21.011.7 ms
- Elide 1.6.0635,510 req/s
- Deno 2.9.7163,511 req/s
- Bun 1.4.2156,974 req/s
- Node.js 24.22.0123,519 req/s
Default serving: one application context, no pipelining, 13-byte response. Versions are shown per runtime.
~/demo # hello world: 10 warmup runs, then 100 measured, no shell
~/demo hyperfine [...]
~/demo bench-chart javascript.json
time · mean ± σ of 100 runs · lower is better
hello.js Delta
elide run hello.js ███▍ 1.43 ms ± 0.06
bun hello.js ███▉ 1.63 ms ± 0.18 1.1× slower
deno run hello.js ███████████████▏ 6.31 ms ± 0.30 4.4× slower
node hello.js ████████████████████████████ 11.70 ms ± 0.90 8.2× slower
~/demo # 24 CPUs per server, wrk on the other 24; 5s warmup, 10s measured
~/demo # defaults: Bun and Deno serve on one thread, Elide on several
~/demo elide server.mjs &
~/demo wrk [...] > elide.txt
~/demo bun server.mjs &
~/demo wrk [...] > bun.txt
~/demo deno serve --port 3000 --host 127.0.0.1 server.mjs &
~/demo wrk [...] > deno.txt
~/demo bench-chart elide.txt bun.txt deno.txt
requests/sec · 12 threads, 256 connections, 10s · higher is better
Delta p50 p99
elide ███████████████████████████████ 635,510 0.38 ms 0.59 ms
deno ████████ 163,511 3.9× slower 1.54 ms 1.58 ms
bun ███████▋ 156,974 4.0× slower 1.60 ms 1.80 ms
wrk -t12 -c256 -d10s after a 5-second warmup. Results vary between runs; this recording shows one.One process, multiple serving contexts
With 24 contexts and HTTP pipelining, the same binary peaked at 10.6M requests/sec and averaged 10.5M across three error-free runs. This tuned workload measures multi-context capacity; the comparison above measures defaults.
Each context runs the entry module and handles requests independently. Enable automatic sizing with --contexts=auto, or choose a count with --contexts=24. The peak run also enabled inline scheduling, io_uring, and pipeline depth 16.
Measured on a Threadripper PRO 9965WX: 24 cores / 48 threads, 128 GB RAM, Ubuntu 26.04.1 LTS, Linux 7.0.0-34-generic, performance governor. Server and client each used twelve physical cores plus SMT over loopback.
elide run --contexts=auto server.mjs
| Setup | Single context | Multi-context |
|---|---|---|
| Peak RPS | 635,510 | 10,697,938 |
| JS contexts | 1 per runtime | 24 in one process |
| HTTP pipeline | — None | ✅ Depth 16 |
| Client | 12 threads · 256 connections | 16 threads · 256 connections |
| Warmup / run | 5s / 10s | 60s / 60s · 3 runs |
| Response | 13 bytes · constant | 9 bytes · URL parsing |
| Server cores | 12 physical + SMT | 12 physical + SMT |
| Scheduling | Default | Inline · io_uring |
| Network | Isolated loopback | Host loopback |
Shared resources, separate application state
Elide’s contexts share runtime resources while keeping JavaScript globals and module state separate. Eligible parsed and JIT-compiled code is reused; telemetry setup, batching, and export are amortized across contexts.
The table compares independent processes with Elide contexts. Request instrumentation and application state still carry per-request or per-context costs. Memory and telemetry savings were not measured; telemetry export was off.
| Resource | Multiple processes | Elide contexts |
|---|---|---|
| Replicas | One process each | One context each |
| Managed heap | Separate | ✅ Shared |
| GC pauses | ✅ Per process | ⚠ May span contexts |
| Parsed / JIT code | Per process | ✅ Shareable code reused |
| Runtime setup | Per process | ✅ Once per process |
| Telemetry pipeline | Per process | ✅ Shared batching/export |
| Request spans | Per request | Per request |
| Process metrics | One stream per process | ✅ One process stream |
| Listener | Port sharing / routing | ✅ One shared listener |
| I/O resources | Per process | Shared topology; per-owner queues |
| JS globals | ✅ Isolated | ✅ Isolated |
| App client pools | Per replica | Per context unless shared by an API |
| Coordination | IPC / external storage | Explicit APIs / external storage |
| CPU scheduling | Process / worker threads | Context owner threads |
| Crash isolation | ✅ Per process | ⚠ Shared process |
| Lifecycle | Manage each process | ✅ One lifecycle |
Multiple runtime processes
Independent heaps and process isolation
One Elide process
Isolated contexts within a shared process
OpenRewrite (experimental)
elide rewrite lists, previews, and applies OpenRewrite recipes. Add recipe modules to dependencies.maven.devPackages; Elide supplies dependency type information without a build plugin.
Supported preconditions use the reference index to select candidate files before parsing. Other recipes scan the full source set. --no-prefilter skips compilation and parses every Java source.
Use the index directly to resolve classes, inspect members, follow references, and find Java or Kotlin usages with elide index used-by.
Experimental in 1.6.0, with compatibility hardening planned for 1.6.1. Dependency annotation values are not yet supported. Review the dry-run diff before applying changes.
elide rewrite --list
elide rewrite org.openrewrite.java.RemoveUnusedImports --dry-run
elide rewrite org.openrewrite.java.RemoveUnusedImports
Publish to Maven
elide publish builds JARs and a POM, then installs them in your local Maven repository. Use --to for Nexus, Artifactory, GitHub Packages, or another configured repository, with checksums and signatures.
CentralPortal publishes a signed bundle to Maven Central. Workspace projects share one deployment; --dry-run previews the files before upload.
import "elide:Publishing.pkl" as Publishing
publishing {
maven {
groupId = "dev.example"
repositories {
["internal"] = "https://repo.example.dev/releases"
["central"] = new Publishing.CentralPortal {}
}
}
}
Export and WebAssembly
elide project export emits JSON, a Maven POM, or an IntelliJ project.
WebAssembly support is experimental: run WASI commands, load modules from JavaScript and TypeScript, or compile JVM applications with elide native-image.
Report, request, file, directly from your agent or editor
Connect your agent or editor to https://elide.help/mcp to search docs, find examples, report bugs, and request features. Review and confirm each report before it becomes a public issue, usually within an hour.
elide agent perf compares commands against another runtime or installed Elide version. It runs offline; elide agent bug --kind perf --json prepares the report data.
Compatibility
Pass rates of build 1.6.0+6e718933f on upstream test suites.
- JavaScript test26299.9%
- Python cpython-core93.8%
- Java javac-jtreg99.9%
- WinterTC wpt-wintertc95.9%
- Node-API node-api86.8%
Elide 1.6.3
Android builds and Compose, Micronaut applications, shared test containers, Python package tools, Maven version overrides, and terminal document rendering.
- Build Android APKs, AAR libraries, and app bundles from
elide.pkl. The Android template includes a Kotlin Compose app; device tasks install, run, debug, and test it using an installed Android SDK. - Enable the Compose compiler with
kotlin.features.compose = trueorelide kotlinc --compose. Declare a compatible Compose runtime dependency; the compiler plugin remains off by default. - Declare Micronaut Core dependencies and Elide installs matching Java annotation processors. Configure the application in Pkl or resource files, run JUnit tests with coverage, and package JVM applications or native executables.
- Declare shared test services in
testing.testcontainers. JavaScript, TypeScript, and JUnit tests receive the same container connection settings, with readiness checks and cleanup after the run. - Install Python packages into the project environment with
elide uv install, or run console tools in isolated environments withelide uv tool run. Requires the optional Python component; only compatible wheels are supported. - Override direct and transitive Maven versions with
dependencies.maven.resolutions. Workspace members inherit root overrides and can replace them by module. - Export build tasks and test results as correlated OpenTelemetry spans, with invocation IDs, task outcomes, and cache status. Export requires a configured telemetry destination; guest CPU profiles remain experimental.
- Render
.pkland.pcffiles as JSON, YAML, or PCF:elide --format=json config.pkl. Without--format, the module controls its output. No Elide project is required. - Read Markdown with
elide README.md: headings, lists, tables, task lists, and highlighted code blocks adapt to the terminal. Piped output is plain; code blocks are displayed without execution.
- Automatic HTTP server telemetry records active requests and request and response body sizes alongside request duration. Throughput counts include unsampled requests.
- Runtime instrumentation logs join the configured OpenTelemetry export, retaining structured fields and trace context. Runtime logging controls apply independently of application logging.
- Heap sizing respects Linux container memory limits instead of sizing against host RAM, avoiding oversized default heaps in memory-limited containers.
- Program arguments after
--reach the program unchanged, including arguments that resemble Elide engine options. - Builds preserve compiler arguments and generated sources for editor project synchronization.
- Android debugging lets
adballocate an available forwarded port, removing the race between choosing a port and opening it. - Telemetry sidecar file descriptors are closed on exec on older glibc systems, so child processes no longer inherit them.
Earlier releases
Versions 1.0 through 1.2 and the pre-1.0 Classic line are retained for teams maintaining older projects. New projects should use the current release line.
Browse the complete release archiveWas this page helpful?