News
What happened in 2025?
Explore our historical records of past releases, completed feature rollouts, security patches, and key project milestones from 2025.
2025-12-21 - Jeasx 2.2.1 released
🎉 Just a patch release with a minor cleanup for explicit path joins in serverless.ts.
Dependency updates: esbuild@0.27.2, jsx-async-runtime@2.0.2, @types/node@24.10.4
2025-12-01 - Jeasx 2.2.0 released
🎉 This release introduces a more flexible configuration approach for the underlying Fastify server. You can now customize all Fastify options (including those for all used plugins) according to your needs, without having to use the formerly fixed and very restrictive set of environment variables. This change was made to eliminate the need for increasingly specific environment variables to customise the default behaviour of Jeasx.
Breaking change: The previously supported environment variables (FASTIFY_BODY_LIMIT, FASTIFY_DISABLE_REQUEST_LOGGING, FASTIFY_REWRITE_URL, FASTIFY_STATIC_HEADERS, FASTIFY_TRUST_PROXY, FASTIFY_MULTIPART_ATTACH_FIELDS_TO_BODY) have been completely removed. While this may seem inconvenient for a minor release, the process of migrating your setup to the new configuration approach usually takes less than a minute. This streamlines the code base and documentation, as these features are presumably seldom used.
To configure Fastify (or a specific plugin), you can now use simple JSON objects which mirror the corresponding Fastify options. Have a look at the linked Fastify documentation for a reference of all existing options:
FASTIFY_SERVER_OPTIONSFASTIFY_COOKIE_OPTIONSFASTIFY_FORMBODY_OPTIONSFASTIFY_MULTIPART_OPTIONSFASTIFY_STATIC_OPTIONS
To optimise the developer experience, it is highly recommended that you use the recently introduced .env.js file to provide these configuration options. Alternatively, you can also provide them via .env or your process environment. Jeasx comes with a minimal set of reasonable Fastify defaults, but you can also overwrite them if necessary.
Some Fastify options, such as rewriteUrl or setHeaders, take a function as a parameter. Jeasx supports this use case by deserialising the stringified function code when the server starts up.
Example configuration
const NODE_ENV_IS_DEVELOPMENT = process.env.NODE_ENV === "development";
export default {
/** @type import("fastify").FastifyServerOptions */
FASTIFY_SERVER_OPTIONS: {
disableRequestLogging: NODE_ENV_IS_DEVELOPMENT,
bodyLimit: 2 * 1024 * 1024,
rewriteUrl: (req) => String(req.url).replace(/^\/jeasx/, ""),
},
/** @type import("@fastify/static").FastifyStaticOptions */
FASTIFY_STATIC_OPTIONS: {
maxAge: NODE_ENV_IS_DEVELOPMENT ? 0 : "365d",
},
/** @type import("@fastify/cookie").FastifyCookieOptions */
// FASTIFY_COOKIE_OPTIONS: {},
/** @type import("@fastify/formbody").FastifyFormbodyOptions */
// FASTIFY_FORMBODY_OPTIONS: {},
/** @type import("@fastify/multipart").FastifyMultipartOptions */
// FASTIFY_MULTIPART_OPTIONS: {},
};
Another improvement has been made by introducing an automatic approach to determine the maximum size of the internal route cache. Depending on the amount of free memory available at startup, the maximum number of cache entries is calculated. This approach strikes a balance, ensuring the cache is large enough for large-scale projects while keeping maximum memory consumption within reasonable limits given the available resources. This means that you no longer need to worry about providing ~~JEASX_ROUTE_CACHE_LIMIT~~ via the environment.
Dependency updates: @types/node@24.10.1
2025-11-10 - Jeasx 2.1.1 released
🎉 Enhanced configuration for @fastify/static, so you can serve pre-compressed static files (see Fastify docs) from public and dist/browser. Just run gzip -rk public dist/browser as post build for gzipping your static assets. This might be useful if you don't want to run a reverse proxy in front of your Jeasx application and serve compressed files nevertheless. Setting up compression for dynamic content can be wired up in userland via a root guard:
import { promisify } from "node:util";
import { gzip } from "node:zlib";
export default function ({ request, reply }) {
this.responseHandler = (payload) => {
if (typeof payload === "string" && request.headers["accept-encoding"]?.includes("gzip")) {
reply.header("content-encoding", "gzip");
return promisify(gzip)(payload);
} else {
return payload;
}
};
}
Updated moduleResolution to bundler in tsconfig.json.
Dependency updates: jsx-async-runtime@2.0.1, fastify@5.6.2, esbuild@0.27.0, @types/node@24.9.2
2025-10-28 - Jeasx 2.1.0 released
🎉 Environment vars can now be loaded from a JavaScript file (.env.js) additionally to existing .env-files. This allows enhanced environment setups depending on your workflows.
Node 24 (LTS) is the official default runtime from now on.
Dependency updates: @fastify/multipart@9.3.0, @fastify/static@8.3.0, @types/node@24.9.1
2025-10-15 - Jeasx 2.0.1 released
🎉 This releases fixes status codes for fallback 404 routes. Due to an unnoticed bug introduced by a minor refactoring, 404-routes were delivered with status=200, now it is the correct status=404 again. This might impact your SEO score, so an update is highly recommended.
Dependency updates: esbuild@0.25.11
2025-10-12 - Jeasx 2.0.0 released
🎉 Approximately one year after the release of Jeasx 1.0 I'm proud to announce the release of Jeasx 2.0.
It's a funny story... every time I think Jeasx is feature-complete, there is still some more room to improve. Although the main idea behind Jeasx development still holds true: focus on a lean and stable core and let developers do all their magic in userland.
This release is focused on security and comes with a major breaking change: all HTML markup is escaped by default from now on, so you don't have to escape dangerous user input on your own anymore. This way the developer experience is improved and the actual performance costs for automatic escaping are neglible due to the reuse of the highly optimized fast-escape-html library.
If you need to include literal HTML in your JSX templates (e.g. HTML snippets from a CMS), you can use a special object syntax to opt out of escaping: {{ html: "<p>Some HTML from a CMS</p>" }}
If you want to migrate from Jeasx 1.0 to Jeasx 2.0 with automatic HTML escaping enabled, you'll need to remove all calls to #escapeEntities() and modify the HTML declaration in your layouts ({{ html: <!DOCTYPE html>" }}). Then you should check where you need to render literal HTML (or other code) and apply the required changes to opt out of escaping (e.g. <div>{ wysiwygContent }</div>; to <div>{{ html: wysiwygContent }}</div>).
If you want to restore the non-escaping behaviour of Jeasx < v2, you can set jsxEscapeHTML = false in the root guard. This way HTML escaping is disabled globally.
Another internal change is the renaming of the directories in the output directory (dist): routes is now called server alongside the browser directory.
Dependency updates: jsx-async-runtime@2.0.0, @types/node@22.18.10
2025-09-29 - Jeasx 1.9.0 released
🎉 This release drops the constraint that you had to put all routes into a dedicated routes-directory and all JavaScript & CSS into a dedicated browser-directory. From now on you can use any directory layout in your projects as you like. You can still use the proven browser/routes layout, but you don't have to.
This feature enables the co-location of server and browser code in the same directory which might be a better default for your workflows.
The only remaining constraint is to mark server routes with brackets (e.g. [news].jsx) and browser-bundled assets as index-files (e.g. index.js or index.css).
Please note: This feature is enabled by dropping the hard coded outbase-directories in the esbuild configuration. If the outbase directory isn't specified, it defaults to the lowest common ancestor directory among all input entry point paths.
If you run into an edge case (e.g. your browser bundles won't load anymore), here's how to fix it: if you store all your assets in browser/assets and request your assets via /assets/..., this won't work anymore, because assets is now the lowest common ancestor directory and is removed by esbuild. Simple fix: just put an empty index.js into browser directory, so this directory is lowest common ancestor directory again.
Bumbed the default ESBUILD_BROWSER_TARGET to "chrome130", "edge130", "firefox130", "safari18".
Dependency updates: fastify@5.6.1, esbuild@0.25.10, @types/node@22.18.6
2025-09-11 - Jeasx 1.8.6 released
🎉 This release bumps dependencies to the latest and greatest versions.
Dependency updates: fastify@5.6.0, fastify/multipart@9.2.1, @types/node@22.18.1
2025-08-13 - Jeasx 1.8.5 released
🎉 This release bumps dependencies to the latest and greatest versions.
Dependency updates: fastify@5.5.0, jsx-async-runtime@1.0.4, esbuild@0.25.9, @types/node@22.17.1
2025-08-03 - Jeasx 1.8.4 released
🎉 This release bumps dependencies to the latest and greatest versions.
Dependency updates: esbuild@0.25.8, @types/node@22.17.0
2025-07-11 - Jeasx 1.8.3 released
🎉 This release bumps dependencies to the latest and greatest versions.
Dependency updates: jsx-async-runtime@1.0.3, esbuild@0.25.6, @types/node@22.16.3
2025-06-13 - Jeasx 1.8.2 released
🎉 This release changes the default options for @fastify/multipart. From now on the default for attachFieldsToBody is keyValues which provides all data for form body requests (e.g. uploads) directly via request.body. Have a look at the Fastify documentation for code examples and options.
This change makes the required code for handling form body requests much easier:
// Change this code...
const file = await request.file();
const upload = await file.toBuffer();
const format = file.fields["format"]["value"];
// ... to this code.
const upload = request.body["upload"];
const format = request.body["format"];
Please note: This change might break your code. If you want to revert to the old behaviour, you can set the following environment variable: FASTIFY_MULTIPART_ATTACH_FIELDS_TO_BODY=false
Dependency updates: fastify@5.4.0, @types/node@22.15.31
2025-05-28 - Jeasx 1.8.1 released
🎉 Just some dependency updates...
Dependency updates: jsx-async-runtime@1.0.2, fastify@5.3.3, fastify/static@8.2.0, esbuild@0.25.5, @types/node@22.15.23
2025-05-12 - Jeasx 1.8.0 released
🎉 This release introduces a custom error handler to provide user-friendly error messages for internal server errors and to facilitate team notifications.
To set up an error handler, simply register it in a route of your choice:
this.errorHandler = async (error) => {
console.error("❌", error);
return <h1>Internal error</h1>;
};
An error handler is called with this as context, allowing easy access to your context setup.
Breaking change: If you use a response handler, you'll need to change the name from this.response to this.responseHandler. This aligns the response handler with the introduced error handler. We apologize for any inconvenience, but since this is a seldom-used feature, we aim to streamline the codebase by aligning it without maintaining deprecated code.
As additional feature, a response handler is now called with this as the context, so you can access your existing context.
Dependency updates: esbuild@0.25.4, @types/node@22.15.17
2025-05-03 - Jeasx 1.7.3 released
🎉 This release introduces a performance improvement by switching the internal route-to-module cache implementation from a JavaScript object to a Map. This change allows for better management of cache entries, enabling the configuration of a maximum cache limit. To take advantage of this, a new configuration option JEASX_ROUTE_CACHE_LIMIT has been added.
Dependency updates: jsx-async-runtime@1.0.1, esbuild@0.25.3, @types/node@22.15.3
2025-04-21 - Jeasx 1.7.2 released
🎉 This release is brings only minor changes:
FASTIFY_STATIC_HEADERS: Apply all matching headers to the current path. Use an empty string ("") as first rule to set default headers, which can be overridden by more specific rules later. Please checkout the updated configuration.
Please note: You may need to adjust your existing configuration by moving the wildcard rule to the top of the JSON file to ensure it can be overridden by more specific rules defined below. env.sh: Removed logging of loaded environment files. Minor refactoring to clean up the code.
Dependency updates: fastify@5.3.2, @types/node@22.14.1
2025-03-31 - Jeasx 1.7.1 released
🎉 This release enhances support for Bun as an alternative JavaScript runtime for both development and production. Use bun -b dev to start development with Jeasx and Bun. With Bun 1.2.8, the entire Jeasx expo functions without any issues. While Node.js remains the primary focus of the project, Bun support will continue to improve. Having multiple options is always beneficial.
Route loading in development has been enhanced. It now relies on the modification time of the module, eliminating the need to calculate a hash for the file content. Additionally, a redundant file existence check for route handlers has been removed, resulting in more streamlined core code.
From now on, source maps for serverless.js are provided to enhance debugging.
Dependency updates: esbuild@0.25.2
2025-03-27 - Jeasx 1.7.0 released
🎉 This release removes pm2 as a dependency and utilizes the powerful file watching capabilities of esbuild directly. This enhancement significantly improves build performance because esbuild only re-compiles linked files. Additionally, sharing code between the server and browser now works seamlessly without any additional configurations.
As an added benefit, Jeasx now works with Bun as an alternative JavaScript runtime, although this setup is not yet recommended for development or production.
Dependency updates: @types/node@22.13.14
2025-03-26 - Jeasx 1.6.3 released
🎉 This release fixes a bug with the recently introduced env file loading. The env files were loaded in the wrong order, so that overwriting existing env variables didn't work.
Dependency updates: fastify@5.2.2, @types/node@22.13.13
2025-03-19 - Jeasx 1.6.2 released
🎉 This release introduces a try/catch block in the central request handler, ensuring that proper error messages are logged. Additionally, it enables sourcemaps for both server and browser code, making debugging a breeze.
To enable sourcemap support for Node.js, add the following code to the root of your project as a .npmrc file:
node-options=--enable-source-maps
If you are using Docker, you need to modify the following lines in your Dockerfile to enable support for .npmrc:
# RUN npx jeasx build
RUN npm run build
# CMD ["npx","jeasx","start"]
CMD ["npm","start"]
2025-03-15 - Jeasx 1.6.1 released
🎉 This releases replaces the dependency on dotenv-flow with a native implementation provided by Node.js (using process.loadEnvFile introduced with Node v20.12.0) to load environment variables from .env-files. The order of loading .env-files is the same as before:
.env.defaults
.env
.env.local
.env.[NODE_ENV] (e.g. .env.development or .env.production)
.env.[NODE_ENV].local (e.g. .env.development.local or .env.production.local)
Breaking change: If you use .env-files to configure Jeasx and deploy to Vercel, please update your vercel.json. You'll need to change "includeFiles": "{node_modules,dist,public}/**/*" to "includeFiles": "./**/*" to make sure Vercel includes the .env-files in the deployment.
Additionally a fix for correctly parsing environment variables to configure Fastify (FASTIFY_DISABLE_REQUEST_LOGGING, FASTIFY_TRUST_PROXY) was implemented.
Dependency updates: jsx-async-runtime@1.0.0, esbuild@0.25.1, pm2@6.0.5
Please note: version 1.6.0 was unpublished from NPM right after the release due to a mistake.
2025-03-09 - Jeasx 1.5.0 released
🎉 This release features two new configurations:
FASTIFY_REWRITE_URL allows you to rewrite incoming URLs. Useful when running behind proxies or when you want to fake URLs.
JEASX_BUILD_ROUTES_IGNORE_WATCH allows watching for changes in src/browser when importing browser code into server code.
Dependency updates: @types/node@22.13.10
2025-03-01 - Jeasx 1.4.1 released
🎉 This release features an updated jsx-async-runtime@0.8.1 which brings typings for SVGs for a better developer experience in the IDE of your choice.
3rd-party dependencies were updated to the latest versions: @fastify/static@8.1.1, @types/node@22.13.5
2025-02-12 - Jeasx 1.4.0 released
🎉 This release adds the route property to the current endpoint handler (e.g., /[index] or /bar/[...path]) to the request object (accessible via request.route). This makes it much easier to calculate trailing path segments for wildcard routes.
Also several dependencies were updated to the latest versions: esbuild@0.25.0, @fastify/static@8.1.0, @fastify/multipart@9.0.3, @fastify/formbody@8.0.3, @types/node@22.13.1
2025-01-18 - Jeasx 1.3.0 released
🎉 We are excited to announce the release of jsx-async-runtime@0.7.1, which now includes proper typings for all HTML attributes in accordance with the Mozilla Developer Network. This ensures that code completion in your IDE for all HTML attributes works now as expected in Jeasx. Special thanks to Rebecca for highlighting this issue!
The updated version of jsx-async-runtime now supports using an array of strings for the class attribute, making it easier to create complex classnames. You can now construct classnames using plain strings or template strings, an array of strings, or an object, covering most use-cases known from other libraries like classnames.
As always, we've updated to the latest versions of our dependencies: fastify/formbody@8.0.2, fastify/multipart@9.0.2, fastify/static@8.0.4, types/node@22.10.7
2025-01-06 - Jeasx 1.2.2 released
🎉 This release is just a minor dependency update: fastify@5.2.1, fastify/cookie@11.0.2, types/node@22.10.5