New: Rethinking Serverless Series Part 1 - Services. Learn more here.
SERVICES

Rethinking Serverless: Services That Actually Work Together

Geno Valente
#Services#Serverless Functions#Raindrop

Rethinking Serverless Series
This is the first blog of the series, Rethinking Serverless, showcasing Raindrop’s Services, Observers, and Actors. You can read up on the full series here:

  • Services (you are here)
  • Observers (coming soon)
  • Actors (coming soon)

Dev engineers who love serverless compute often highlight these three top reasons:

  1. Elimination of Server Management: This is arguably the biggest draw. With serverless, developers are freed from the burdens of provisioning, configuring, patching, updating, and scaling servers. The cloud provider handles all of this underlying infrastructure, allowing engineers to focus solely on writing code and building application logic. This translates to less operational overhead and more time for innovation.
  2. Automatic Scalability: Serverless platforms inherently handle scaling up and down based on demand. Whether an application receives a few requests or millions, the infrastructure automatically adjusts resources in real-time. This means developers don’t have to worry about capacity planning, over-provisioning, or unexpected traffic spikes, ensuring consistent performance and reliability without manual intervention.
  3. Cost Efficiency (Pay-as-you-go): Serverless typically operates on a “pay-per-execution” model. Developers only pay for the compute time their code actually consumes, often billed in very small increments (e.g., 1 or 10 milliseconds). There are no charges for idle servers or pre-provisioned capacity that goes unused. This can lead to significant cost savings, especially for applications with fluctuating or unpredictable workloads.

But what if the very isolation that makes serverless appealing also hinders its potential for intricate, multi-component systems?

The Serverless Communication Problem

Traditional serverless functions are islands. Each function handles a request, does its work, and forgets everything.

Traditional serverless functions are islands. Each function handles a request, does its work, and forgets everything. Need one function to talk to another? You’ll be making HTTP calls over the public internet, managing authentication between your own services, and dealing with unnecessary network latency for simple internal operations.

This architectural limitation has held back serverless adoption for complex applications. Why would you break your monolith into microservices if it means every internal operation becomes a slow, insecure HTTP call, and/or any better way of having communications between them is an exercise completely left up to the developer?

Introducing Raindrop Services

Services in Raindrop are stateless compute blocks that solve this fundamental problem. They’re serverless functions that can work independently or communicate directly with each other—no HTTP overhead, no authentication headaches, no architectural compromises.

Think of Services as the foundation of a three-pillar approach to modern serverless development:

Let’s dive into how Services can be used to make your life easier.

Two Types of Services for Different Needs

Public Services: Your Application’s Front Door

Public services are exactly what you’d expect—serverless functions accessible via unique URLs. They handle external requests, manage authentication, and serve as entry points to your application.

Public Services

// raindrop.manifest
service "my-api" {
  domain {
    cname = "my-unique-service"
  }
}

When deployed, this service becomes accessible at my-unique-service.<org-id>.lmapp.run. Perfect for APIs, webhooks, and any user-facing functionality.

Internal Services: The Secret Sauce

Here’s where things get interesting. Internal services don’t need public URLs—they’re designed to be called by other services within your application. But unlike traditional serverless functions, they can be invoked directly without HTTP calls.

This is service binding in action: efficient, secure communication between your services without the networking overhead.

Internal Services

// raindrop.manifest
service "my-api" {}

Service Bindings: Direct Internal Communication

The magic happens when services call each other. Instead of making HTTP requests, services invoke methods directly on other services. It’s like having a private, high-speed network between your functions. Below are the public and internal services in action:


// Service A (public-facing)
export default class extends Service<Env> {
  async fetch(request: Request): Promise<Response> {
// Direct call to internal service - no HTTP, no URLs needed
    const response = await this.env.SERVICE_B.processData({
      userId: getUserId(request)
    });
    return response;
  }
}

// Service B (internal-only)
export default class extends Service<Env> {
  async processData(input: any): Promise<Response> {
// Your business logic here
    return new Response("Processed successfully");
  }
}

Notice what’s missing? No URLs, no authentication headers, no HTTP status code handling between your own services. Service A calls a method on Service B as naturally as calling any other function, but with all the benefits of independent scaling and deployment.

Building Scalable Applications with Services

Clean Architecture Made Simple

With service bindings, you can structure applications the way they should be structured: with clear separation between public interfaces and internal business logic.


application "store" {
// Public-facing services
  service "api" { domain { cname = "store-api" } }
  service "admin" { domain { cname = "admin-panel" } }

// Internal services
  service "inventory" {}
  service "payments" {}
  service "notifications" {}
}

Your public API service handles incoming requests, validates input, and coordinates with internal services for inventory checks, payment processing, and notifications. Each service has a single responsibility, scales independently, and can be updated without affecting the others.

Microservices Without the Complexity

Traditional microservices require service discovery, load balancing, and complex networking. With Raindrop Services, all of that is handled automatically. Your services discover each other through the manifest configuration, calls are automatically load-balanced, and the platform handles failures gracefully.

You get the benefits of microservices—independent scaling, ease of deployment, and paying for what you use only—without the operational overhead.

With Raindrop Services you can build using our manifest file without the complexity

What’s Coming Next

Services solve the fundamental communication problem in serverless architectures, but they’re just the beginning. Modern applications need more than request-response patterns—they need to react to events and maintain state across requests.

Part 2 - Observers (coming soon): Learn how to build reactive applications that respond to changes automatically:

Part 3 - Actors (following): Discover stateful serverless computing:

Together, Services, Observers, and Actors form a complete platform for building applications that were near impossible with traditional serverless architectures.

Try Services Today

Ready to experience serverless functions that actually work together? Check out the complete Services documentation and start building applications the way they should be built.

In our next post, we’ll explore how Observers let you build reactive applications that respond to changes automatically—no polling, no complex event systems, just clean, efficient event-driven code.

Getting Started is Easy

Ready to make your data smarter with your own AI agents? We’re offering:

Sign up for your account today →

Want to explore costs first? Take a look at our pricing here. To get in contact with us or for more updates, join our Discord community.

Subscribe to our newsletter

← Back to all Blogs & Case Studies