Encore
Encore is a backend development platform that automatically provisions, configures, and manages cloud infrastructure based on your Go code. It simplifies building and deploying cloud-native applications by allowing you to focus purely on business logic.
You are an expert in Encore, mastering its unique infra-from-code paradigm for building scalable, cloud-native Go applications. You adeptly leverage its static analysis capabilities to provision and manage cloud infrastructure automatically, streamline API development, integrate with managed services, and orchestrate complex microservice architectures with unparalleled developer experience.
## Key Points
1. **Install the Encore CLI:**
2. **Initialize a new Encore application:**
3. **Define your first service and API:**
4. **Run your application locally:**
* **Define Clear API Contracts:** Use Go structs for API request and response bodies. This ensures type safety and allows Encore to generate robust clients and documentation.
* **Write Comprehensive Tests:** Encore services are standard Go code, making them easy to test with Go's built-in testing framework. Focus on unit and integration tests for your business logic.
## Quick Example
```bash
go install encore.dev/cli/encore@latest
```
```bash
encore app init my-encore-app
cd my-encore-app
```skilldb get baas-skills/EncoreFull skill: 252 linesEncore — Infra from Code Backend Development
You are an expert in Encore, mastering its unique infra-from-code paradigm for building scalable, cloud-native Go applications. You adeptly leverage its static analysis capabilities to provision and manage cloud infrastructure automatically, streamline API development, integrate with managed services, and orchestrate complex microservice architectures with unparalleled developer experience.
Core Philosophy
Encore's core philosophy centers on eliminating the "undifferentiated heavy lifting" of cloud infrastructure management. By analyzing your Go code, Encore automatically understands your application's architecture—identifying APIs, database schemas, secrets, and inter-service dependencies—and provisions the necessary cloud resources (compute, databases, queues, caches, etc.) on AWS, GCP, or Azure. This "infra-from-code" approach means you define your infrastructure implicitly through your application code, freeing you from writing YAML, configuring Terraform, or managing Kubernetes.
You choose Encore when you want to accelerate backend development, reduce operational overhead, and maintain a high level of code quality and consistency across your services. It's particularly well-suited for teams building full-stack applications, microservices, or APIs that require robust, scalable cloud infrastructure without the steep learning curve and complexity traditionally associated with cloud-native development. Encore promotes a Go-first approach, leveraging Go's strong typing and tooling to provide a seamless development and deployment experience from local machine to production.
Setup
Encore requires the Encore CLI to be installed, which is used to manage your applications, run them locally, and deploy them to the cloud.
-
Install the Encore CLI:
go install encore.dev/cli/encore@latest -
Initialize a new Encore application:
encore app init my-encore-app cd my-encore-appThis creates a basic project structure with a
main.gofile and anencore.appconfiguration file. -
Define your first service and API:
Create a new directory for your service, e.g.,
pkg/greeting, and a filepkg/greeting/service.go.// pkg/greeting/service.go package greeting import ( "context" "encore.dev/beta/encore" ) //encore:api public path=/hello/:name func SayHello(ctx context.Context, name string) (*GreetingResponse, error) { return &GreetingResponse{Message: "Hello, " + name + "!"}, nil } type GreetingResponse struct { Message string } -
Run your application locally:
encore runEncore will compile your application, start local services, and expose your API on
localhost:4000. You can then access it:curl http://localhost:4000/hello/World.
Key Techniques
1. Exposing an HTTP API Endpoint
Define an API endpoint using the //encore:api comment directive. Encore automatically generates a strongly typed client for inter-service communication and provisions a public HTTP endpoint.
// pkg/user/service.go
package user
import (
"context"
"encore.dev/beta/encore"
)
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
//encore:api public method=GET path=/users/:id
func GetUser(ctx context.Context, id string) (*User, error) {
// In a real app, you'd fetch this from a database or another service.
// For demonstration, return a mock user.
if id == "123" {
return &User{ID: "123", Name: "Alice Smith", Email: "alice@example.com"}, nil
}
return nil, encore.Errorf("user not found")
}
//encore:api public method=POST path=/users
func CreateUser(ctx context.Context, params *CreateUserParams) (*User, error) {
// In a real app, generate ID, save to DB, etc.
newUser := &User{
ID: "new-user-id", // Mock ID
Name: params.Name,
Email: params.Email,
}
return newUser, nil
}
type CreateUserParams struct {
Name string `json:"name"`
Email string `json:"email"`
}
2. Integrating with an Encore SQL Database
Encore allows you to define managed SQL databases (Postgres) directly in your code. It handles provisioning, migrations, and connection management.
// pkg/product/service.go
package product
import (
"context"
"database/sql"
"encore.dev/beta/encore"
_ "github.com/lib/pq" // PostgreSQL driver
)
//encore:service
type Service struct {
db *encore.SQLDatabase
}
//encore:startup
func (s *Service) Startup(ctx context.Context) error {
// Encore automatically creates and manages a PostgreSQL database.
// The `migrations` directory contains SQL files for schema management.
s.db = encore.NewSQLDatabase("productdb", encore.SQLDatabaseConfig{
Migrations: "./migrations",
})
return nil
}
type Product struct {
ID string `json:"id"`
Name string `json:"name"`
Price float64 `json:"price"`
}
//encore:api public method=GET path=/products/:id
func (s *Service) GetProduct(ctx context.Context, id string) (*Product, error) {
var p Product
err := s.db.QueryRow(ctx, "SELECT id, name, price FROM products WHERE id = $1", id).Scan(&p.ID, &p.Name, &p.Price)
if err == sql.ErrNoRows {
return nil, encore.Errorf("product not found")
} else if err != nil {
return nil, encore.Wrap(err, "failed to get product")
}
return &p, nil
}
And your migration file pkg/product/migrations/1_initial_schema.up.sql:
CREATE TABLE products (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
price NUMERIC(10, 2) NOT NULL
);
3. Inter-Service Communication
Encore automatically generates strongly typed clients for your services, enabling seamless and type-safe communication between them.
// pkg/order/service.go
package order
import (
"context"
"encore.dev/beta/encore"
"my-encore-app/pkg/product" // Import the product service
"my-encore-app/pkg/user" // Import the user service
)
//encore:service
type Service struct {
products product.Service // Encore injects the client for the product service
users user.Service // Encore injects the client for the user service
}
type CreateOrderParams struct {
UserID string `json:"userId"`
ProductID string `json:"productId"`
Quantity int `json:"quantity"`
}
type Order struct {
ID string `json:"id"`
UserID string `json:"userId"`
Product *product.Product `json:"product"`
Quantity int `json:"quantity"`
Status string `json:"status"`
}
//encore:api public method=POST path=/orders
func (s *Service) CreateOrder(ctx context.Context, params *CreateOrderParams) (*Order, error) {
// Call the user service to verify the user
u, err := s.users.GetUser(ctx, params.UserID)
if err != nil {
return nil, encore.Wrap(err, "failed to get user")
}
// Call the product service to get product details
p, err := s.products.GetProduct(ctx, params.ProductID)
if err != nil {
return nil, encore.Wrap(err, "failed to get product")
}
// Logic to create an order...
newOrder := &Order{
ID: "order-id-123", // Mock ID
UserID: u.ID,
Product: p,
Quantity: params.Quantity,
Status: "Pending",
}
return newOrder, nil
}
Best Practices
- Leverage Encore's Static Analysis: Treat warnings from
encore runorencore deployas errors. Encore's analyzer guides you to correctly define services, APIs, and infrastructure, preventing common cloud configuration mistakes. - Use Built-in Services: Whenever possible, use
encore.SQLDatabase,encore.Cache,encore.Queue,encore.Secret, etc., instead of manually integrating with external cloud services. This simplifies provisioning, scaling, and operational management. - Define Clear API Contracts: Use Go structs for API request and response bodies. This ensures type safety and allows Encore to generate robust clients and documentation.
- Implement Robust Error Handling: Return
errorfrom your API functions. Useencore.Errorffor user-facing errors andencore.Wrapto add context to underlying errors. Encore automatically logs unhandled errors. - Structure Your Project Logically: Organize services into
pkg/servicenamedirectories. Keep related types, API definitions, and database migrations within their respective service directories. - Write Comprehensive Tests: Encore services are standard Go code, making them easy to test with Go's built-in testing framework. Focus on unit and integration tests for your business logic.
- Monitor and Observe: Utilize the Encore Cloud Dashboard for logs, metrics, traces, and operational insights into your deployed applications. Integrate with external tools as needed via Encore's observability features.
Anti-Patterns
- Manual Infrastructure Configuration. Don't attempt to manually configure cloud resources (e.g., via Terraform or CloudFormation) that Encore is designed to manage. This bypasses Encore's guarantees and introduces unnecessary complexity and potential conflicts. Let Encore handle the infrastructure from your code.
- Ignoring Encore's Static Analysis. Treating static analysis warnings as non-critical. These warnings often indicate issues that will prevent deployment or lead to runtime errors. Address all warnings and errors proactively.
- Directly Managing Cloud SDKs. Avoid using cloud provider SDKs (e.g.,
aws-sdk-go) directly within your Encore services for common resources like databases or queues. Instead, leverage Encore's managed primitives (encore.SQLDatabase,encore.Queue, etc.) for better integration, observability, and portability. - Over-reliance on Global State. Favor explicit dependencies and clean service boundaries. Global variables or singleton patterns can make services harder to test and reason about, especially in a distributed microservices environment.
- Complex Monolithic Services. While Encore handles services well, avoid creating one massive
//encore:servicethat encompasses too much unrelated logic. Break down functionality into smaller, focused Encore services to improve maintainability, scalability, and independent deployment.
Install this skill directly: skilldb add baas-skills
Related Skills
Appwrite
Appwrite self-hosted BaaS with database, auth, storage, and serverless functions
AWS Amplify
AWS Amplify BaaS with AppSync GraphQL, Cognito auth, S3 storage, and Lambda functions
Backendless
Backendless BaaS with real-time database, user authentication, Cloud Code,
Clerk Auth
Clerk authentication service with pre-built UI components, session management, and multi-framework support
Convex
Convex real-time backend with reactive queries, mutations, and serverless functions
Firebase
Firebase BaaS with Firestore, Authentication, Cloud Functions, and Hosting