Functions on orkestr, now with pip and npm

Dependencies, more runtimes, live build progress, friendlier failures: what changed in orkestr Functions since the beta. EU-hosted serverless, no DevOps tax.

Stefan 4 min read

When we shipped orkestr Functions in beta a week ago, we called dependencies the #1 thing on the list. The runtime had Node and Python’s standard libraries and that was it - any function that needed requests or axios or anything from PyPI/npm was stuck. That’s the gap we just closed, plus a handful of things we noticed while we were in there.

Here’s what’s live now.

Dependencies, the way you’d expect them

Each function gets a Dependencies textarea on the Code tab. Paste packages, deploy, they install.

requests
httpx==0.27.0
pydantic>=2

For Python that’s requirements.txt syntax, one per line, version pins welcome. For Node it’s the same shape:

express
axios@^1.6
zod

The Node side accepts plain names (orkestr synthesizes a package.json for you) or, if you need scripts or engines, you can paste a raw package.json and it goes through unchanged.

Under the hood, the build pipeline wraps your handler in a Dockerfile that does the install layer first, the handler last:

COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt
COPY handler.py /app/handler.py

Order matters. Handler-only edits (the common case once you’ve got deps right) hit the Kaniko build cache and rebuild in roughly five seconds. Changing the dep list invalidates the cache and reinstalls. That’s 10 to 30 seconds for a small Python project, longer for the heavy stuff (pandas, scikit-learn, the ML stack). That’s the trade.

The cache is shared across functions, so if two of yours both pin requests==2.33.1, the second one builds for free.

Four Python and four Node versions

The beta had Node 20 and Python 3.12, picked because they were the current stable when we shipped. We added the surrounding versions so you can match an existing toolchain:

  • Python: 3.10, 3.11, 3.12, 3.13
  • Node.js: 18 (deprecated), 20, 22 (LTS), 24

The picker shows them as a version row under the language buttons. Node 18 reached upstream EOL in April 2025. We left it in because some teams pin to it, but it carries a deprecated badge in the UI. Pick a version that still gets security updates if you can.

Defaults stay at Python 3.12 / Node 20 to keep existing functions on what they were created with.

Live deploy progress

The old deploy button gave you nothing regarding the function was live or it wasn’t. With dependency installs taking up to two minutes for a fat Python stack, that wasn’t enough and that felt confusing.

Now the dashboard streams every stage:

  1. Selecting node
  2. Building image (installing dependencies)
  3. Starting container
  4. Configuring DNS
  5. Function is live

Each step shows a spinner while it’s running, a check when it’s done, a red X if it failed. The “Building image” line adds the parenthetical when you have deps so you understand why it’s slow.

A button that knows when there’s nothing to deploy

Lambda’s deploy button greys out when your editor matches the live version. Ours didn’t. Jk. That’s fixed, you can’t deploy unmodified code anymore.

The Deploy button now shows three states:

  • Up to date (greyed, with a check) when the editor, deps, env vars, and auth mode all match the live container.
  • Save & Deploy (blue) when there are unsaved edits in the code tab.
  • Deploy (blue) when there are saved changes pending or the function never deployed.

Hovering the disabled state shows when you last deployed. Editing env vars in the Settings tab also surfaces a banner there pointing back to the header button - one of those small things that kept tripping people up.

Useful failure messages

You typo a dep name, the build fails. That part is unchanged and unavoidable. What’s new is what you see.

Before: ten lines of raw pip / npm stderr in the stepper. Decipherable, not friendly.

Now, when the failure matches a known pattern, the bubble leads with a one-liner:

Couldn’t find requst on PyPI - check the spelling of your dependency.

ERROR: Could not find a version that satisfies the requirement requst …

Currently matched: pip “could not find a version” / “no matching distribution”, pip’s Invalid requirement parse error, npm 404s on the registry, and npm’s ETARGET “no matching version found” for bad version pins. Anything else falls through to the raw stderr unchanged. We’d rather show you the truth than mislabel a real error.

A note on real-world testing: we tried expres (typo of express) and the deploy succeeded, which surprised us until we checked. There’s a typo-squatted package called expres on npm. Fun way to remember why supply-chain hygiene matters.

What’s still missing

Same honest list shape as the beta announcement, smaller now:

  • No CLI or git-based deploy yet. You still paste code in the dashboard.
  • No per-invocation logs in the Metrics tab. You can read container logs in the Logs tab today, but it’s tail-only.
  • No custom domains on a function. Subdomain pattern stays fn-<name>.<your-tenant>.orkestr.run.
  • Only HTTP trigger. No queue, no cron. For now.

If you were holding off because deps were the blocker, the Starter plan is still free - one function included - and requests works out of the box now. Head to Functions to spin one up.

Love to hear from you if you have any feedback: stefan at orkestr dot eu.


Ship your next app on orkestr

EU-hosted. Push your code - live in seconds.

Start deploying for free