Skip to main content
View all authors

Freezing, Gzip, & Console Enhancements

ยท 2 min read

Hi ๐Ÿ‘‹

A new release is out โ€” v0.0.52 ๐Ÿš€

Here are a few highlights:
๐ŸงŠ Longer default freezing thresholds
โœ… Gzipped HTML
๐Ÿ” Allowed Callers
๐Ÿ›  CLI Improvements
๐Ÿ–ฅ Polished Console UI

Checkout the release notes for details ๐Ÿ‘‰ Release v0.0.52 ยท junobuild/juno

Let me know if anything looks fishy โ€” and happy coding! ๐Ÿ‘จโ€๐Ÿ”ง


๐Ÿ–ฅ๏ธ Two screenshots from the Console new features

The new โ€œNotificationsโ€ component:

Notifications UI

The overall look: collapsible menu, redesigned tabs, more prominent actions, and more.

Console UI Update


As a side note on this release: aside from the custom domain feature, I think itโ€™s now possible to configure your entire project โ€” including authentication, data, storage, and emulator โ€” directly within the Juno config file. Plus with type safety as the cherry on top.

This is especially handy for maintainability or if your project can be forked.

Hereโ€™s an example config that shows where and how the project is deployed, which headers to apply to assets, defines the structure of that data, and which image to use when running the emulator with Podman:

import { defineConfig } from "@junobuild/config";

/** @type {import('@junobuild/config').JunoConfig} */
export default defineConfig({
satellite: {
ids: {
development: "jx5yt-yyaaa-aaaal-abzbq-cai",
production: "fmkjf-bqaaa-aaaal-acpza-cai"
},
source: "build",
predeploy: ["npm run build"],
storage: {
headers: [
{
source: "**/*.png",
headers: [["Cache-Control", "max-age=2592000"]]
}
]
},
collections: {
datastore: [
{
collection: "notes",
read: "managed",
write: "managed",
memory: "stable"
}
]
}
},
emulator: {
runner: {
type: "podman"
},
satellite: {}
}
});

Documentation ๐Ÿ‘‰ https://juno.build/docs/reference/configuration

Build and Publish Serverless Functions with GitHub Actions

ยท 7 min read


One of the principles that shaped Juno from day one was the idea of building apps with full ownership โ€” no hidden infrastructure, no opaque servers.

No hypocrisy either.

If developers are encouraged to deploy code in containers they control, it feels inconsistent to rely on centralized infrastructure โ€” like AWS or other Web2 cloud providers โ€” to manage deployment pipelines or run the platform. With the exception of email notifications, Juno currently runs entirely on the Internet Computer โ€” and that's a deliberate choice.

That doesn't mean being stubborn for the sake of it. It just means trying to push things forward without falling back on the old way unless absolutely necessary.

At the same time, developer experience matters โ€” a lot. It shouldn't take a degree in DevOps to ship a backend function. Developers who would typically reach for a serverless option should be able to do so here too. And for those who prefer to stay local, it shouldn't feel like a downgrade โ€” no one should be forced into CI automation if they don't want to.

That's why the new GitHub Actions for serverless functions are now generally available โ€” for those who want automation, not obligation.


๐Ÿš€ Automated Deployments, No Compromiseโ€‹

With the latest release, it's now possible to:

  • Build serverless functions written in TypeScript or Rust
  • Automatically publish them to a Satellite
  • Optionally propose or directly apply upgrades

All within a GitHub Actions workflow. No manual builds, no extra setup โ€” just code, commit, and push.

This makes it easier to fit Juno into an existing CI/CD pipeline or start a new one from scratch. The logic is bundled, metadata is embedded, and the container is ready to run.


๐Ÿ” What About Security?โ€‹

You might ask yourself: "But what about the risk of giving CI full control over my infrastructure?"

That's where the improved access key (previously named "Controllers") roles come in.

Instead of handing over the master key, you give CI just enough access to do its job โ€” and nothing more.

Here's how the roles break down in plain terms:

  • Administrator โ€“ Full control. Can deploy, upgrade, stop, or delete any module. Powerful, but risky for automation. Might be useful if you're spinning up test environments frequently.

  • Editor (Write) โ€“ Ideal for CI pipelines that deploy frontend assets or publish serverless functions. Can't upgrade those or stop and delete modules. A good default.

  • Submitter ๐Ÿ†• โ€“ The safest option. Can propose changes but not apply them. Someone still needs to review and approve in the Console or CLI. No surprises, no accidents.

Use Editor for most CI tasks โ€” it gives you automation without opening the blast radius.

Prefer an extra layer of review? Go with Submitter and keep a human in the loop.


๐Ÿงฐ Local or CI: Your Choiceโ€‹

Nothing changes in the approach for developers who prefer local development. The CLI remains a first-class tool for building and deploying.

All the new capabilities โ€” from publishing functions to proposing or applying upgrades โ€” are available not just in GitHub Actions or the Console UI, but also fully supported in the CLI.

In fact, the CLI has been improved with a neat addition: you can now append --mode development to interact with the emulator. This allows you to fully mimic production behavior while developing locally. And of course, you can also use any mode to target any environment.

juno functions upgrade --mode staging
juno deploy --mode development

๐Ÿ›ฐ๏ธ Satellite's CDNโ€‹

While building serverless functions was never an issue, enabling GitHub Actions to publish and deploy without giving away full control introduced a challenge. How do you let CI push code without handing it the keys to everything?

That's where the idea of a sort of CDN came in.

Each Satellite now has a reserved collection called #_juno/releases. It's like a staging area where CI can submit new WASM containers or frontend assets. If the access key has enough privileges, the submission is deployed right away. If not, it's stored as a pending change โ€” waiting for someone to approve it manually via the Console or CLI.

This builds on the change-based workflow that was added to the Console last year. Funny enough, it brought the Console so close to being a Satellite itself that it became... basically a meta example of what you can build with Juno.

And here's the cherry on top: because there's now a CDN tracking versions, developers can rollback or switch between different function versions more easily. A new CDN tab in the Console UI (under Functions) gives you access to all past versions and history.


๐Ÿ–ผ๏ธ Frontend Deployments, Tooโ€‹

Frontend deployment now benefits from the same change-based workflow. By default, when you run juno deploy or trigger a GitHub Action, the assets are submitted as pending changes โ€” and applied automatically (if the access key allows it).

Want to skip that workflow? You still can. The immediate deployment path remains available โ€” handy if something fails, or if you just prefer to keep things simple.


๐Ÿ› ๏ธ GitHub Actions for Serverless Functionsโ€‹

Alright, enough chit-chat โ€” here's how to publish your serverless functions on every push to main, straight from CI:

publish.yml
name: Publish Serverless Functions

on:
workflow_dispatch:
push:
branches: [main]

jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 24
registry-url: "https://registry.npmjs.org"

- name: Install Dependencies
run: npm ci

- name: Build
uses: junobuild/juno-action@full
with:
args: functions build

- name: Publish
uses: junobuild/juno-action@full
with:
args: functions publish
env:
JUNO_TOKEN: ${{ secrets.JUNO_TOKEN }}

๐ŸŒธ One Action, Two Flavorsโ€‹

Noticed the @full in the previous step?

That's because the GitHub Action now comes in two flavors:

  • junobuild/juno-action or junobuild/juno-action@slim โ€“ perfect for common use cases like deploying frontend assets or running simpler CLI tasks. No serverless build dependencies included, so it's faster and more "lightweight" (relatively, it still uses Docker underneath...).

  • junobuild/juno-action@full โ€“ includes everything you need to build and publish serverless functions, with Rust and TypeScript support. It's heavier, but it does the job end to end.

The right tool for the right job. Pick what fits.


๐Ÿงญ Where This Is Goingโ€‹

This release isn't just about smoother deployments โ€” it's a step toward making Juno feel like real infrastructure. Though, what is โ€œreal infrastructureโ€ anyway? Whatever it is, this one doesn't come with the usual baggage.

Developers get to choose how they ship โ€” locally or through CI. They get to decide what gets deployed and who can do it. They're not forced to rely on some big tech platform for their infra if they don't want to. And thanks to the new CDN and access control model, fast iteration and tight control can finally go hand in hand.

If you've been waiting for a way to ship backend logic without giving up on decentralization โ€” or if you just like things working smoothly โ€” this one's for you.

Go ahead. Build it. Push it. Submit it. Ship it.

To infinity and beyond,
David


Stay connected with Juno by following us on X/Twitter.

Reach out on Discord or OpenChat for any questions.

โญ๏ธโญ๏ธโญ๏ธ stars are also much appreciated: visit the GitHub repo and show your support!

Analytics Campaign Tracking

ยท One min read

Hi ๐Ÿ‘‹

A new release v0.0.50 is out! ๐Ÿš€

This one brings two improvements to the Analytics:

๐Ÿ“ฃ Campaign tracking is now supported! Just use standard UTM tags in your links โ€” traffic sources like newsletters, ads, and social posts will show up directly in your dashboard. No extra setup needed.

# For example
https://myapp.com/?utm_source=newsletter&utm_medium=email&utm_campaign=spring-launch

๐Ÿค– Bot detection has also been improved by using HTTP headers directly from the container smart contract (instead of those passed in the requests). More accurate and secure that way.

Enjoy! ๐Ÿงช๐Ÿ“Š


Analytics UTM tracking

Monitoring Health Check

ยท One min read

I just shipped a release focuses solely on updates to the Console UI.

The main change is the addition of a new Health Check section under โ€œMonitoringโ€, along with a clearer breakdown of memory metrics.

I also revisited the notion of the โ€œauto-refill thresholdโ€, as the previous description was misleading or partial.

Lastly, the step related to the โ€œauthentication domainโ€ in the hosting wizard has been simplified.

All these changes are, of course, documented.

Happy weekend โ˜€๏ธ

Health Check UI

Lighter Analytics Client

ยท One min read

This new release brings a major upgrade to Juno Analytics โ€” now powered by native HTTP requests with no more web workers or IndexedDB.

The JS client is now over 90% (๐Ÿ”ฅ) smaller (just 3KB gzipped!), and the dashboard supports paginated views, top time zones, and OS metrics.

There are a few breaking changes (โ€ผ๏ธ), so check the notes if youโ€™re using analytics โ€” and make sure to upgrade your Orbiter and JS libraries at the same time โš ๏ธ.

Reach out if you have questions, happy to help!

New Juno Analytics Dashboard UI

Announcing Serverless Functions in TypeScript

ยท 5 min read


One of the goals with Juno has always been to make building decentralized, secure apps feel like something you're already used to. No weird mental models. No boilerplate-heavy magic. Just code that does what you expect, without touching infrastructure.

And with this release, we're taking another step in that direction: You can now write serverless functions in TypeScript.

If you're a JavaScript developer, you can define backend behavior right inside your container. It runs in a secure, isolated environment with access to the same hooks and assertions you'd use in a typical Juno Satellite.

No need to manage infrastructure. No need to deploy a separate service. Just write a function, and Juno takes care of the rest.

Cherry on top: the structure mirrors the Rust implementation, so everything from lifecycle to data handling feels consistent. Switching between the two, or migrating later, is smooth and intuitive.


โœจ Why TypeScript?โ€‹

Rust is still the best choice for performance-heavy apps. That's not changing.

But let's be real: sometimes you just want to ship something quickly. Maybe it's a prototype. Maybe it's a feature you want to test in production. Or maybe you just want to stay in the JavaScript world because it's what you know best.

Now you can.

You get most of the same tools, like:

  • Hooks that react to document or asset events (onSetDoc, onDeleteAsset, etc.)
  • Assertions to validate operations (assertSetDoc, etc.)
  • Utility functions to handle documents, storage, and even call other canisters on ICP

The JavaScript runtime is intentionally lightweight. While it doesn't include full Node.js support, we're adding polyfills gradually based on real-world needs. Things like console.log, TextEncoder, Blob, and even Math.random โ€” already covered.


๐Ÿ” Designed for Interopโ€‹

The approach to writing serverless functions in Rust and TypeScript is aligned by design. That means if you outgrow your TS functions, migrating to Rust won't feel like starting from scratch. The APIs, structure, and flow all carry over.

Start scrappy, scale gracefully.


๐Ÿ‘€ A Taste of Itโ€‹

Here's how simple it is to react to a document being created or updated:

import { defineHook, type OnSetDoc } from "@junobuild/functions";

export const onSetDoc = defineHook<OnSetDoc>({
collections: ["posts"],
run: async (context) => {
const data = context.data.data.after.data;
console.log("New post created:", data);
}
});

And here's for example how you'd validate a document before accepting it โ€” using Zod for a clean, readable schema:

import { z } from "zod";
import { defineAssert, type AssertSetDoc } from "@junobuild/functions";
import { decodeDocData } from "@junobuild/functions/sdk";

const postSchema = z.object({
title: z.string().min(5, "Title must be at least 5 characters long")
});

export const assertSetDoc = defineAssert<AssertSetDoc>({
collections: ["posts"],
assert: (context) => {
const data = decodeDocData(context.data.data.proposed.data);
postSchema.parse(data);
}
});

That's it. No APIs to expose, no infra to manage. Just code that runs where your data lives.


๐Ÿ–ฅ๏ธ Local-First Developmentโ€‹

Alongside TypeScript support, we've rethought the local development experience.

Instead of providing a partial local environment, the mindset shifted to mimicking production as closely as possible.

You still get a self-contained image with your Satellite, but now you also get the full Console UI included. That means you can manage and test your project locally just like you would on mainnet.

See this other blog post for all the details.


๐Ÿงฐ Zero Tooling, Just Codeโ€‹

Here's the beautiful part: even though your serverless functions are written in TypeScript, they're bundled and embedded into a Satellite module that's still compiled in Rust behind the scenes.

But you don't need to install Rust. Or Cargo. Or ic-wasm. Or anything that feels complicated or overly specific.

All you need is Node.js and Docker. The container takes care of the rest: building, bundling, embedding metadata and gives you a ready-to-run Satellite that runs locally and is ready to deploy to production.

In short: just code your functions. The container does the heavy lifting.


๐Ÿ“ก Already in the Wildโ€‹

This isnโ€™t just a feature announcement โ€” serverless functions in TypeScript are already live and powering real functionality.

I used them to build the ICP-to-cycles swap on cycles.watch, including all the backend logic and assertions. The whole process was documented over a few livestreams, from setup to deployment.

If you're curious, the code is on GitHub, and thereโ€™s a playlist on YouTube if you want to follow along and see how it all came together.

A screenshot of cycles.watch that integrates with OISY and use serverless functions in TypeScript to swap ICP for cycles


โ–ถ๏ธ Try It Outโ€‹

We've put together docs and guides to help you get started. If you're already using the Juno CLI, you're just one juno dev eject away from writing your first function or start fresh with npm create juno@latest.

To infinite and beyond,
David


Stay connected with Juno by following us on X/Twitter.

Reach out on Discord or OpenChat for any questions.

โญ๏ธโญ๏ธโญ๏ธ stars are also much appreciated: visit the GitHub repo and show your support!

A Production-like Local Dev Environment

ยท 4 min read


Until now, running a local project meant spinning up an emulator with just enough to build with a single default Satellite container for your app.

That worked. But it wasnโ€™t the full picture.

With the latest changes, local development now mirrors the production environment much more closely. You donโ€™t just get a simplified setup โ€” you get the actual Console UI, orchestration logic, and almost a full infrastructure that behaves like the real thing.

This shift brings something most cloud serverless platforms don't offer: production-level parity, right on your machine.


๐Ÿค” Why This Mattersโ€‹

Local development isnโ€™t just about getting things to run. Itโ€™s about understanding how your project behaves, how it scales, and how it integrates with the platform around it.

With this shift, you build with confidence that what works locally will work in production. You donโ€™t need to guess how things will behave once deployed โ€” youโ€™re already working in an environment that mirrors it closely.

It also helps you gradually get familiar with the tools that matter, like the Console UI. You learn to use the same workflows, patterns, and orchestration logic that apply when your app goes live.

This removes a lot of friction when switching environments. There's less surprise, less debugging, and a lot more flow.

Itโ€™s local development, but it finally feels like the real thing.


๐Ÿ“ฆ Whatโ€™s Includedโ€‹

The new local environment is powered by the junobuild/skylab Docker image, now used by default in templates and tooling.

It brings together everything you need to build and test your project in a real setup:

  • Console UI โ€” the same interface used in production on https://console.juno.build

  • More preinstalled services โ€” including Internet Identity, ICP Ledger and Index, NNS Governance and Cycles minting (CMC)

  • Live reload โ€” serverless functions written in Rust or TypeScript automatically reload on change

  • Orchestration logic โ€” the flow of creating Satellites, managing configurations, and testing behaviors mirrors production

No custom scripts. No extra setup. Everything is handled by the tooling.


๐Ÿงช What About CI?โ€‹

Not every project needs a UI.

Thatโ€™s why the lightweight junobuild/satellite image still exists โ€” and still works just as it always has. Itโ€™s ideal for CI pipelines, isolated app testing, or local startup when you donโ€™t need the Console and more infrastructure.

This shift in approach isnโ€™t a breaking change. It adds a new default, but doesnโ€™t remove what was already there.

Looking ahead, there's an intention to simplify scripting even further by allowing Datastore and Storage definitions directly in the main juno.config file. The goal is to eventually phase out juno.dev.config and unify configuration โ€” but thatโ€™s for the future.

For now, everything remains compatible. You choose what fits best.


๐Ÿš€ How to Get Startedโ€‹

There are two ways to start using the new local environment โ€” whether youโ€™re beginning fresh or updating an existing project.

๐Ÿ†• Starting from Scratchโ€‹

Everything is already set up in the templates. Just run:

npm create juno@latest

This will scaffold your project with the latest configuration, using the junobuild/skylab image and the updated local workflow.

๐Ÿ”„ Migrating an Existing Projectโ€‹

If you already have a project configured for local development and want to switch to the new approach:

  1. Update the CLI:
npm i -g @junobuild/cli
  1. Remove your juno.dev.config.ts (or the JavaScript or JSON equivalent)

  2. Update your docker-compose.yml to use the junobuild/skylab image (adjust paths as needed for your project):

services:
juno-skylab:
image: junobuild/skylab:latest
ports:
# Local replica used to simulate execution
- 5987:5987
# Little admin server (e.g. to transfer ICP from the ledger)
- 5999:5999
# Console UI (like https://console.juno.build)
- 5866:5866
volumes:
# Persistent volume to store internal state
- juno_skylab:/juno/.juno
# Your Juno configuration file.
# Notably used to provide your development Satellite ID to the emulator.
- ./juno.config.mjs:/juno/juno.config.mjs
# Shared folder for deploying and hot-reloading serverless functions
# For example, when building functions in TypeScript, the output `.mjs` files are placed here.
# The container then bundles them into your Satellite WASM (also placed here),
# and automatically upgrades the environment.
- ./target/deploy:/juno/target/deploy/

volumes:
juno_skylab:

Thatโ€™s it โ€” youโ€™re good to go.


โœ… Closing Thoughts

This shift removes a lot of friction between idea and execution.

You build in the same structure, use the same tools, and follow the same workflows you'd use in production โ€” but locally, and instantly.

Local development finally feels like you're already in production, just without the pressure.


Stay connected with Juno by following us on X/Twitter.

Reach out on Discord or OpenChat for any questions.

โญ๏ธโญ๏ธโญ๏ธ stars are also much appreciated: visit the GitHub repo and show your support!

Create Juno Just Got a Big Upgrade

ยท One min read

๐Ÿš€ Create Juno just got a big upgrade!

โœจ Local dev is now the default for apps (!)
๐Ÿ›  Scaffold serverless functions
๐Ÿ›ฐ Sputnik preview (WIP)
๐Ÿ“ฆ Updated all template dependencies
๐ŸŽ“ Onboarding revamped

Give it a try ๐Ÿ˜Ž

With NPM:

npm create juno@latest

With Yarn:

yarn create juno

With PNPM:

pnpm create juno

Internet Identity Domain

ยท One min read

Morning! Great news for the Juno community, which has always used identity.internetcomputer.org as the default domain for authentication.

Internet Identity now supports passkeys on both of its domains!

This means it should no longer matters whether devs or users sign in via identity.internetcomputer.org or identity.ic0.app โ€” the registered identity should work seamlessly across both. There are a few limitations, which is why II may prompt you to register your current device.

As a result, Iโ€™ve just launched a new, clean sign-in page with a single call to action! ๐Ÿš€

To address potential sign-in issues, the page still offers domain-specific methods as a fallback. Plus, I added a brand-new footer accessible on scrollโ€”kind of really happy with that design. ๐Ÿ˜ƒ

๐Ÿ‘‰ https://console.juno.build/

Cool, cool, cool!


References:

Cleaned login page