05/06/24

Encore.ts

Encore is now available for TypeScript, powered by a new high-performance Rust runtime.

6 Min Read

It's Day 1 of Launch Week and we're kicking off with a big one...

Introducing: Encore.ts

Encore has simplified building event-driven and distributed systems in Go for years. Today we're launching Encore.ts, bringing the same simple workflow to TypeScript developers everywhere.

It's designed around a new Open Source Backend Framework, which makes it very simple to create backend services and APIs, and use cloud infrastructure resources like databases and Pub/Sub.

It's powered by a high-performance distributed systems runtime in Rust, integrated with the standard Node.js runtime for full compatibility with the Node.js ecosystem, offering a major performance upgrade:

  • 7x Request throughput (req/s)
  • -85% Response latency

Encore's Open Source Backend Framework

Encore.ts is designed around a new Open Source Backend Framework, which makes it simple to create backend services and APIs, and use cloud infrastructure resources. It removes the need for the typical microservices boilerplate and infrastructure configuration.

The Backend Framework provides a declarative way to use common cloud primitives, like:

  • APIs and Services
  • SQL Databases
  • Pub/Sub topics and subscriptions
  • Caches
  • Cron jobs
  • Secrets

Example: Hello World

Encore lets you easily define type-safe, idiomatic TypeScript API endpoints. It's done in a fully declarative way, enabling Encore to automatically parse and validate the incoming request and ensure it matches the schema, with zero boilerplate.

To define an API, use the api function from the encore.dev/api module to wrap a regular TypeScript async function that receives the request data as input and returns response data. This tells Encore that the function is an API endpoint. Encore will then automatically generate the necessary boilerplate at compile-time.

Here’s “Hello World” in Encore.ts:

import { api } from "encore.dev/api"; export const get = api( { expose: true, method: "GET", path: "/hello/:name" }, async ({ name }: { name: string }): Promise<Response> => { const msg = `Hello ${name}!`; return { message: msg }; } ); interface Response { message: string; }

To run it, you simply use encore run and the Open Source CLI will automatically set up your local infrastructure.

Example: Using PostgreSQL

Setting up a PostgreSQL database is just three lines of code in Encore.ts. You define the database schema by creating migration files in a directory named migrations within an Encore service package. Encore takes care of the rest.

import { SQLDatabase } from "encore.dev/storage/sqldb"; // Create the todo database and assign it to the "db" variable const db = new SQLDatabase("todo", { migrations: "./migrations", }); // Then, query the database using db.query, db.exec, etc.

This means, with Encore, you don’t need to mess around with database passwords or Docker Compose manifests, you just do encore run.

Example: Event-driven applications using Pub/Sub

Publishers & Subscribers (Pub/Sub) let you build systems that communicate by broadcasting events asynchronously. This is a great way to decouple services for better reliability and responsiveness. Encore's Backend Framework lets you use Pub/Sub in a cloud-agnostic declarative fashion.

Like with databases, we can just define the Pub/Sub topic directly in our application. Encore takes care of setting it all up.

For example, to create a topic with events about user signups:

import { Topic } "encore.dev/pubsub" export interface SignupEvent { userID: string; } export const signups = new Topic<SignupEvent>("signups", { deliveryGuarantee: "at-least-once", });

Like before, encore run will spin up all our services, and all the Pub/Sub infrastructure you have defined. There's no need to use any emulators or other workarounds.

Unmatched Node performance, powered by Rust

To enable Encore's functionality in TypeScript, we’ve created a high-performance distributed systems runtime in Rust. It integrates with the standard Node.js runtime for executing JavaScript code, ensuring 100% compatibility with the Node.js ecosystem.

The Rust runtime does everything from handling incoming requests and making API calls, to querying databases and using Pub/Sub. It even handles all application observability, like distributed tracing, structured logging, and metrics.

Using Rust leads to a massive performance increase over standard Node.js, increasing throughput by 7x and reducing response latency by 85%.

What’s really cool: Encore has zero NPM dependencies, improving security and speeding up builds and application startup times.

How it works

  1. Node.js starts up and initializes the Encore Rust runtime, which begins accepting incoming requests, parsing and validating them against the API schema.
  2. The Encore Runtime then passes on the request to your application code, and waits for the response, before sending it back out over the wire.
  3. When your application uses infrastructure resources, like querying databases or publishing PubSub messages, it hands that over to the Rust runtime for faster execution.

This means that the Node.js event loop — which is single-threaded — can focus on executing your business logic. Everything else happens in Encore’s multi-threaded Rust runtime.

Enhanced type-safety for distributed systems

Normally with TypeScript, the type information is lost at runtime. But Encore is different.

Encore uses static code analysis to parse and analyze the TypeScript types you define, and uses the API schema to automatically validate incoming requests, guaranteeing complete type-safety, even at runtime. This means no more confusing exceptions because a required field is missing.

Encore uses it's understanding of your application to orchestrate local infrastructure, so ou only need encore run to start your application locally, including all the necessary infrastructure.

It also sets up the Local Development Dashboard that gives you built-in tools for very productive development, including:

  • API Explorer
  • Service Catalog with automatic API documentation
  • Architecture Diagrams
  • Distributed Tracing

Automated DevOps in your cloud on AWS & GCP

Using the cloud can be tough. Especially for startups, for two main reasons:

  • It requires a lot of specific expertise, just to set things up.
  • Even if you do have experience, it takes way too much time away from development.

That’s why we created Encore’s Cloud Platform. And if you’re a startup dealing with cloud complexity, it might be for you.

It fully automates DevOps activities like provisioning and configuring cloud infrastructure, and CI/CD. You can even choose how to run your app, for instance, using serverless or Kubernetes.

This lets you use the full capabilities of AWS or GCP, without the distractions.

It even helps you deal with security, by automatically implementing best practices. So you never need to worry about whether your database is publicly accessible, or if you have backups enabled. It can also implement least-privilege security, ensuring your services only have access to the resources they need.

How it works

When you use Encore’s Backend Framework, Encore is able to parse and understand your application’s architecture and infrastructure requirements.

Behind the scenes, this takes the form of a graph, which Encore’s Cloud Platform uses to understand what infrastructure to provision and how it should be configured.

Encore Automates DevOps

Try it yourself

If you want to try it out, install Encore and check out the example apps using encore app create. It’s free and open source.

macOS
Windows
Linux
Brew
$ brew install encoredev/tap/encore

If you have any questions or just want to hang out with other developers, join our community on Discord.

Encore

This blog is presented by Encore, the development platform for building robust type-safe distributed systems with declarative infrastructure.

Like this article?
Get future ones straight to your mailbox.

You can unsubscribe at any time.