All jobs

Compare Express 5 and Hono for an Express Project

Yes. An agent ports one module of your Express app to Express 5 and to Hono in a sandbox, runs tests and a benchmark on each, and writes up the difference.

What the agent does

The agent clones the repository into its own sandbox and reads what a port would have to carry. In an Express app like gothinkster/node-express-realworld-example-app, package.json pins express at ~4.18.1 with body-parser, cors and express-jwt, Prisma 4 against Postgres (src/prisma/schema.prisma), Jest 29 with ts-jest, and Nx 17 driving build, serve and test. The module the prompt names is the article routes: src/app/routes/article/article.controller.ts registers 11 handlers on one Router, from GET /articles with offset, limit, tag, author and favorited query parameters to the comment and favorite routes, and calls into the 652-line article.service.ts.

Before porting anything it records a baseline on the default branch. It starts Postgres in the sandbox, applies the migrations in src/prisma/migrations, runs the seed from src/prisma/seed.ts, and runs npx nx test. That suite matters for the comparison: the Jest tests in src/tests/services/ replace Prisma with jest-mock-extended and test the service functions, so they never touch the router. A port that breaks routing would still pass them. So the agent writes one set of HTTP tests against the running server for the article routes (list, feed, get by slug, create, update, delete, favorite, comments), runs them on the baseline, and uses the same file on both branches. It also notes that e2e/src/server/server.spec.ts expects { message: 'Hello API' } while src/main.ts answers { status: 'API is running on /api' }, so that test fails before any change and counts against neither port.

The Express 5 branch is the smaller change, and the agent lists each edit it needed. Express 5 forwards a rejected promise from an async handler to the error middleware, so the try { … } catch (error) { next(error) } blocks in every handler can go. req.query becomes a getter, path syntax moves to path-to-regexp 8, and express-jwt must still produce the UnauthorizedError that src/main.ts turns into a 401. The Hono branch rewrites the controller as a Hono app mounted at /api, swaps cors and body-parser for Hono's own middleware, and replaces express-jwt with a JWT check that keeps getTokenFromHeaders in src/app/routes/auth/auth.ts working, because that helper accepts both Token and Bearer prefixes and RealWorld clients send Token. Since only the article routes move, the Hono branch serves them beside the remaining Express routers, and the agent says how it joined the two.

Then it measures the same things on the baseline and both branches: the shared HTTP tests, npx nx build, lines changed from git diff --stat, and a short load test with a tool such as autocannon against GET /api/articles and one authenticated route, with the same seeded data, connection count and duration on each. Each number in the report is from a command in the run's transcript. Both branches stay in the sandbox; nothing is pushed.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Clone https://github.com/gothinkster/node-express-realworld-example-app. Start Postgres in the sandbox, apply the Prisma migrations, run the seed, and record a baseline with npx nx test and npx nx build. Write one set of HTTP tests for the article routes in src/app/routes/article/article.controller.ts that runs against the live server, and run it on the baseline. On two throwaway branches, port the article routes to Express 5 and to Hono, keeping the Token and Bearer prefixes that src/app/routes/auth/auth.ts accepts and the 401 that src/main.ts returns. Run the HTTP tests, the Jest suite, the build and the same autocannon benchmark against GET /api/articles and one authenticated route on the baseline and each branch. Write comparison.md with the diff size, test results, build result, timings, every change each port needed and the trade-offs you hit. Note any test that already fails on the baseline. Open no pull request and push nothing."
}
  1. Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
  2. Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
  3. Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

What comes back

What comes back is comparison.md, a file on the session with a download link that works for an hour. It has a table with one column each for the baseline, Express 5 and Hono, and rows for lines changed, files touched, the HTTP test results, the Jest results, the build result, and the benchmark's requests per second and latency percentiles. Under the table, each port has a list of the changes it needed and why, so the size of the diff can be read as work rather than as a number.

The trade-offs section is where the run earns its keep: what each option did to error handling, authentication and middleware in this codebase, which dependencies each one dropped or needed, and anything the agent had to work around. The session's transcript keeps every command it ran, including each benchmark with its full output, so the numbers can be checked or re-run.

Before deciding, a reviewer checks that the benchmark settings were the same across the three columns, that the HTTP tests covered the routes the team cares about, and that the Hono branch's mixing with Express is acceptable as a temporary state or would need the rest of the routers ported too. To take the next step, send the same session a follow-up asking it to open a pull request from the branch you chose; the sandbox wakes with both branches still on its disk.

Run it on every framework major release

A comparison like this goes stale when either side ships a major version. Have a job on your server watch the release feeds you care about and send this request when one appears, with an Idempotency-Key built from the version so one release starts one run.

Set a webhook URL on the API key, and Rush POSTs run.completed with the session_url when the run finishes. Your server attaches the new comparison.md to the architecture decision it informs, so the record shows how the numbers moved between releases.

The use case this job follows, with its automation and trigger: Produce a report or file, no repo.

Why run it on Rush?

A fair spike needs a database, a seeded dataset, three checkouts and a benchmark that is not competing with an editor, a browser and a dev server. In a Rush sandbox the agent gets a machine of its own for it: Postgres, the seed, both branches and the load tests run there, and nothing on your laptop changes.

What makes the write-up trustworthy is that the claims come with their commands. Every row in the table points back to a step in the transcript with its output, so the comparison can be argued about on the evidence. You can run the same request on several services at once, one run each, up to the key's concurrent run limit, and compare the reports side by side.

Frequently asked questions

Will the agent change my repository?

No. The prompt clones the repository into the sandbox, does the work on throwaway branches there, and says to push nothing and open no pull request. The result is a report you download.

Why port only one module instead of the whole app?

One module with real routing, authentication and database access shows the shape of the migration and gives a like-for-like benchmark, at a fraction of the work of a full port. The report says what the rest of the app would add, such as the other routers and middleware still on Express.

Are the benchmark numbers meaningful?

They compare the three versions on the same sandbox, data and settings, so the relative difference is the useful part. They are not production numbers: the sandbox is not your production hardware, and the report gives the exact command so you can repeat it where it matters.

Can I compare Express 5 with Fastify instead?

Yes. Change the second target in the prompt; the baseline, the shared HTTP tests and the measurements stay the same, and the report gets a Fastify column instead of a Hono one.