Technical insights and announcements from the Pext team.
A recap of the week of 29 June: Bun is now a supported runtime for Pext-converted code after the WASM swap for PCRE and LibXML removed the last native-binding blockers, a new closed-world conversion flag ingests the whole source set as one unit for stronger inter-file reasoning, and an early POC of pext-viz visualises the control flow of a converted project.
Read moreDesign notes on a Pext SAPI built around async/await. Under closedWorld the transpiler ingests the entire source set and colours the control flow, propagating I/O calls up through the call graph to the top-level web handlers. Async execution comes out of a single conversion, no post-processing. Caveats: autoloaders, magic methods, and destructors all fire at arbitrary points and cannot await.
Series finale of the ten-part Leaving PHP series. Every prior post was tactical. Step back and the real question is strategic: for a decade-scale platform bet, where will the talent, the libraries, the integrations, and the AI tooling be in 2030? PHP will not disappear, but "will not disappear" is a low bar for a technology bet, and the ecosystem momentum is elsewhere.
A recap of the week of 22 June: an arrays refactor bringing Pext closer to the packed-array shape used by PHP internally, static scope emission with vanilla let bindings when the semantics allow it, and a best-effort tokenizer that lets opensourcepos convert with byte-for-byte token parity against PHP.
How Pext uses Node cluster mode to reproduce the php-fpm request lifecycle: a master process bound to the FastCGI socket, a pool of workers, requests dispatched to the pool by Apache mod_proxy_fcgi. The result is a runtime that slots in where php-fpm used to sit, with .htaccess and every existing Apache configuration untouched.
Part 9 of the ten-part Leaving PHP series. The old argument against leaving PHP was that a rewrite is impossibly expensive. Big-bang rewrites are still bad, but the option set has widened: strangler-fig behind a shared gateway, file-by-file transpilation with a compatibility runtime, and hot-path extraction. Migration is no longer a binary, and most of the gradient is cheaper than it looks.
A recap of the week of 15 June: NanoCMS moving from PHP 7 to PHP 8 and running under Apache in pext, a streamlined WASM pipeline for PHP C dependencies like PCRE and LibXML that avoids the pain of porting Node bindings across versions, and ten end-to-end REST scenarios for opensourcepos cross-checked between PHP and Pext.
Part 8 of the ten-part Leaving PHP series. PHPStan, PHP-CS-Fixer, Pest, Psalm, and PHPUnit are all excellent. Vite, Cargo, and go fmt are also excellent, and one command wires them into your project. In PHP the assembly is your problem, and that assembly is a daily tax for onboarding, for greenfield projects, and for anyone who would rather focus on the product than on the toolchain.
How pext models PHP namespaces as a runtime map of slots instead of relocating files under PSR-4, and the partial overhaul that landed this week: case-insensitive lookups, kind-aware resolution between functions, classes and constants of the same name, canonical FQN preservation through use-aliases, namespace-versus-class disambiguation, and a faster cold path for use-heavy scripts.
voku/portable-ascii is at 100%, but the interesting story is transliteration. PHP leans on ICU through the Transliterator class, and ICU has no clean equivalent in JavaScript. A survey of the landscape (the transliteration npm package, Node's embedded ICU, unicode-org/icu4x, the deprecated icu-transliterator binding), why stable Pext ships a patched transliteration package, and why a custom ICU4x WASM build stays reserved for enterprise.
A recap of the week of 8 June: a new analyze step that statically infers what each function does with its variables, grab-bag locals lowered to plain JS bindings when nothing needs the dynamic scoping, an optimized $this emission backed by its invariants, and the converted PHPUnit suite running in about half the time it did last week.
pext-vanillify is an opt-in AI-driven pass that runs after the deterministic transpiler and rewrites non-idiomatic JS patterns into shapes a JS engineer would have written. First two skills: detokenizing Kint's caller introspection into named parameters, and replacing CodeIgniter 4's class-from-file resolution with a PSR-4-backed lookup.
Part 7 of the ten-part Leaving PHP series. PHP grew up on cPanel and the defaults still encode that world: superglobals, .htaccess, php.ini, mod_php. Containers, serverless, and edge runtimes are the 2026 deployment story, and every PHP target there is an adapter project working around the language's assumptions.
A recap of the week of 1 June: a second framework roadmap for CodeIgniter 4 alongside Laravel, new runtime modules for password, hash, sessions, and MySQL, continued work on the embedded -S server and ini parameter handling, a full audit of how each PHP type is represented in JS, and the removal of Rector as a pre-processing step.
CodeIgniter 4 is now a side roadmap running alongside Laravel. New runtime support for password, hash, sessions, and a working MySQL client, the framework boots (autoloader, configuration, CLI commands), and a POC against opensourcepos boots the application and runs login and logout end to end.
Part 6 of the ten-part Leaving PHP series. Fibers landed in 8.1, Swoole and ReactPHP and AmPHP exist, and yet writing async PHP in 2026 still puts you on a side path. The libraries, the frameworks, and the team mental model all assume the request-response shape.
A recap of the week of 25 May: multiple new SAPIs including the embedded -S server, a TypeScript port of the bootstrap module that mirrors PHP for extension loading and ini reading, and the centralized in-memory storage that separates per-request execution contexts.
Part 5 of the ten-part Leaving PHP series. In a TypeScript-everywhere stack the type of an API response is one source of truth, consumed by server and client. PHP plus JavaScript leaves you with two type systems that do not talk, and the productivity gap is now too large to ignore.
Phase 2 of the Laravel roadmap closes with a 100% pass rate on every utility package. Five new runtime modules landed alongside it (ctype, filter, intl, mbstring, sessions), and the roadmap deliberately deviates to cross-check against PhpSpreadsheet and CodeIgniter 4 before continuing.
A recap of the week of 18 May: opening transpilation of PhpSpreadsheet and its test suite, an initial conversion of CodeIgniter 4, multi-process testing finished for nette/schema and nette/utils, and a transpiler-side cleanup pass that trims superfluous emitted JavaScript.
A walk through the Pext request lifecycle: shared-nothing bootstrap on par with PHP, drop-in replacement for the PHP CLI, separated centralized storage that opens the door to async and threaded SAPIs, and transpile-time inference for the I/O calls that would need refactoring to take advantage of them.
Part 4 of the ten-part Leaving PHP series. Composer works, Packagist works, Laravel and Symfony are mature. None of that is the problem. The problem is that the cutting edge of every new category ships JavaScript and Python first, and PHP fifth, late, or never.
A recap of the week of 11 May: cron-expression at 100%, magic-method fixes for __call and __invoke, by-ref and copy-on-write across call boundaries, dynamic member syntax, a new pext CLI with a pext.ini equivalent, a TypeScript pipeline finished end-to-end, native new for static instantiation, plus variadic coercion, call_user_func by-ref, and grouped use.
How Pext brought dragonmantank/cron-expression to 100%. The work was almost entirely in the datetime module: timezone arithmetic, DST transitions, the add/sub/diff family, the long tail of PHP-specific date format characters, and a cache for Intl.DateTimeFormat that turned a slow run into a reasonable one.
Part 3 of the ten-part Leaving PHP series. A decade of incremental type-system additions (7.0 through 8.4), still no generics in the language, and the refactoring confidence gap that hits hardest on a 200,000-line codebase compared to TypeScript, Kotlin, and Python with Pyright.
How Pext reached 100% on egulias/email-validator: a new pext-multibyte-string module covering the mb_* family, a pext-network module for DNS lookups, the codepoint-vs-byte fixes the parser needed, and the CRLF handling that closed the folded-header tests.
A recap of the week of 04 May: a partial audit of the arrays module, doctrine/lexer at 100%, egulias/email-validator at 92% on the back of two new runtime modules (pext-network, pext-multibyte-string), hamcrest-php at 90%, myclabs/deep-copy at 83% with a full clone implementation, and datetime improvements driven by cron-expression.
How Pext reached 100% on the composer/semver test suite. Two hurdles that had nothing to do with the library itself: a PHPUnit 9 binary bootstrapped through a Symfony symlink, and dozens of eval calls that generate version_compare code which had to see the caller scope.
Part 2 of the ten-part Leaving PHP series. The architectural cost of shared-nothing in 2026: a 10–30× throughput gap on TechEmpower, the connection-pool math that hits Postgres ten times harder than Node, and what you give up when you reach for Swoole, RoadRunner, or FrankenPHP.
A recap of the week of 27 April: a complete audit of the math module against every PHP version since 4, composer/semver and doctrine/inflector at 100%, a deep analysis of string literal encodings, experimental TypeScript output, and initial support for static variables inside functions.
How Pext brought the math module to full PHP parity: dual test suites, version-aware ValueError throwing, operators that branch on PHP_INT_SIZE at runtime, the C99 corner cases in pow, comparable-aware max/min, operator-overridable pow, dual rounding mode acceptance, and inlining as the next step.
Part 1 of a ten-part series on why teams are leaving PHP in 2026. A data-driven look at the talent market: a ~40% relative drop in seven years, an aging bench, only 15.2% of new programmers picking PHP first, and a salary curve that punishes hiring at the wrong end.
A recap of the week of 20 April: brick/math at 100%, bcmath support, numeric conversion and coercion finalized, PCRE comprehensively tested, the Laravel roadmap published, and the Foundations phase complete.
How Pext reached 100% on the brick/math test suite: keeping PHP int and float distinct in JavaScript, fixing static $var, handling overflow, tuning preg_match flags, scope resolution, and operator coercion.
An honest comparison of the three ways to move a PHP codebase to Node.js. Speed, cost, risk, lock-in, and the transition problem that neither AI nor manual rewrites acknowledge.
A recap of the week of 13 April: exporter at 92.5%, operator and type coercion improvements, math module testing, X account launch, blog filtering, and program execution support.
sebastian/exporter is small but technically demanding. A look at the three challenges it posed for Pext: destructor timing, object-to-array casting, and property visibility.
An honest look at how Pext's modular runtime, inspectable output, escrow licensing, and two-phase roadmap are designed to de-risk migration, not trap you in a new ecosystem.
A recap of the week of 6 April: website launch, refcounting destructors, sebastian/exporter at 82%, reflection line numbers, and comment-attribute preprocessing.
A deep dive into transpiling PHPUnit: 54k lines, 4,500+ tests, and one of the most demanding codebases in the PHP ecosystem.
The Pext presentation website goes public. A look at what we built, what it does, and where we go from here.