• Use Cases
  • Pricing
  • Security
  • Docs
Sign InStart free

The outbound integration layer for SaaS products: emit once, then let Meshes handle routing, retries, fan-out, and delivery history.

© Copyright 2026 Meshes, Inc. All Rights Reserved.

About
  • About
  • Security
  • Blog
  • Contact
  • FAQ
Product
  • Pricing
  • Demo
  • Integrations
  • Guides
  • Changelog
  • Status
Compare
  • All comparisons
  • Build vs buy
  • vs Paragon
  • vs Merge
  • vs n8n
  • vs Zapier
  • vs Make
Use Cases
  • All use cases
  • Embedded CRM sync
  • Per-tenant Slack
  • HMAC webhooks
  • Multi-env workspaces
  • Payment failed
  • User signup fan-out
  • Churn prevention
  • Trial expired events
Developers
  • Documentation
  • Agents
  • Tools
  • API Reference
  • MCP Server
  • llms.txt
Legal
  • Terms of Service
  • Privacy Policy
  • Acceptable Use Policy
  • Cookie Policy

WorkflowEnvironment isolation

Separate Dev, Staging, and Production With Per-Environment Workspaces

Workspaces are not only for external customers. Every SaaS has internal tenants that need the same isolation: dev, staging, and production. Running one workspace per environment, each with its own publishable key and destinations, keeps test-shaped data out of real customer tools.

Start freeView documentation

Event signal:user.created| Destination:Slack| Use case:Multi-Environment Workspaces| Typical setup:~20 minutes

Workflow outcome

The product event is small. The downstream effect is not.

Three Meshes workspaces — dev, staging, and production — each with its own Slack connection pointing at a different channel and its own publishable key your app uses per environment.

One product emit path that reads the current environment's publishable key from configuration and routes user.created to the right workspace. No branching, no feature flags, no test data bleeding into prod alerts.

Why teams care

This is the kind of workflow buyers judge fast

Integration code and test data do not mix well. The moment you wire up a production Slack channel or CRM, every dev branch, integration test, and staging deploy becomes a chance to fire off a real side effect by accident.

The cleanest pattern is to treat environments the same way you treat customers: separate workspaces. Each environment has its own publishable key, its own connections, and its own event history.

Because workspaces are the same primitive you use for external customers, onboarding a new environment is the same operation you already automate for tenants — you do not learn two different patterns.

Even when the code behaves identically across environments, the connections behind each workspace point somewhere different, so there is nothing to cross-contaminate.

What it depends on

The supporting pieces behind a credible rollout

These pages stay focused on the workflow outcome, but the setup still needs the right workspace, destination connection, and event path underneath.

Three Meshes workspaces

Create dev, staging, and production workspaces in your Meshes organization. Each will own its own connections and publishable key.

Read more

A Slack workspace or sandbox per environment

Decide which Slack channel each environment should post to. Production usually points at a real ops channel; dev and staging usually point at deliberately noisy channels.

Read more

Environment-aware configuration in your app

Your code needs a way to load the current environment's publishable key at runtime — usually through environment variables.

Event emission path

Your product needs to emit user.created (or the event you pick) through the publishable-key events client.

Read more

The source event

The payload that creates the downstream business outcome

The payload shape is identical across environments. The difference is entirely in which publishable key you pass to the events client — that decides which workspace, and therefore which Slack connection, receives the event.

Event payload

user.created
{
  "user_id": "usr_homer",
  "email": "homer@springfield-npp.dev",
  "account_id": "acc_springfield",
  "environment": "staging",
  "created_at": "2026-04-17T12:00:00Z"
}

What matters most

  • user_id + email

    Identifies the user consistently across environments so staging logs look structurally like production logs.

  • account_id

    Keeps tenant context visible in each environment for debugging without crossing the environment boundary.

  • environment

    Optional but useful metadata so the Slack message clearly labels where the event originated, reducing the chance of mistaking a staging alert for a production one.

  • created_at

    Lets each environment correlate its events with its own monitoring timeline.

Field mapping view

What the destination needs from the event

Event fieldDestination targetWhy it matters
emailSlack message bodySame mapping in every environment — only the Slack connection and channel differ.
environmentSlack message header or prefixLabel dev/staging messages visibly so readers never confuse them with production.
account_idReference blockKeep the reference shape identical across environments so debugging is symmetric.
created_atTimestampSame timestamp mapping everywhere so tests behave like production traffic.

The destination connection

The destination matters, but the connection quality matters just as much

In each environment workspace, create a Slack connection that points at a channel appropriate for that environment. Dev and staging usually connect to deliberately noisy channels; production connects to the real ops channel. The rule shape is the same in all three workspaces — only the connection changes.

  • Create a Slack connection in the dev workspace and point it at a channel your team is comfortable flooding with test traffic.
  • Repeat the connection setup in staging with its own channel, so staging deploys never page on-call in production.
  • Create the production Slack connection last, pointing at the channel where real alerts should land.
  • Name each connection consistently across environments (for example, 'ops-alerts') so the rule you author looks identical everywhere.
Slack IntegrationMeshes quickstart

Where Meshes matters

The product stays simple while the destination still gets the right shape

Most teams do not need another destination. They need the destination to stay in sync without embedding its delivery quirks, retries, and mapping logic into the product code path.

Event

user.created

Destination

Slack

Use case

Multi-Environment Workspaces

Docs

Slack Integration

Author the same rule in each workspace: bind user.created to a Slack Send Message action targeting the per-environment connection. Because the rule shape is identical, you can script rule creation against the management API and apply it to every environment workspace the same way.

  • Keep rule names consistent across environments. That makes delivery history easy to scan when you are comparing behavior between dev and prod.
  • Consider including the environment label in the Slack template so readers never misread a staging alert as production.
  • Because the publishable key is what selects the workspace, you do not need environment branching in your code — the environment variable is the only thing that changes.
  • If you use the management API to maintain rules, apply schema updates to every environment so nothing drifts over time.

A sample event

The product-side code stays close to the business event

This is the part teams like: the source event stays readable and product-shaped while Meshes owns the destination-facing complexity.

TypeScript example

One emit call stays close to the business event

import MeshesEventsClient from '@mesheshq/events';

// WORKSPACE_PUBLISHABLE_KEY is set per environment:
//   dev    → pk_dev_...    → dev workspace    → #dev-alerts
//   stage  → pk_stage_...  → staging workspace → #staging-alerts
//   prod   → pk_prod_...   → production workspace → #alerts
const events = new MeshesEventsClient(
  process.env.WORKSPACE_PUBLISHABLE_KEY!,
);

await events.emit({
  event: 'user.created',
  payload: {
    user_id: 'usr_homer',
    email: 'homer@springfield-npp.dev',
    account_id: 'acc_springfield',
    environment: process.env.APP_ENV,
    created_at: new Date().toISOString(),
  },
});

Destination outcome

Run the emit path from each environment and confirm the message lands in that environment's Slack channel — and only in that channel. Try it from dev first, then staging, then production.

Send EventsSDK docs

Operational visibility

Delivery history is where this stops feeling like glue code

The difference between a nice demo and a usable product workflow is whether you can see what happened when the destination is slow, misconfigured, or unavailable.

In Meshes

What a healthy workflow looks like

  • In each workspace, confirm the event was received under that environment's event history.
  • Check that only the expected Slack channel received the message for each test run.
  • Flip the environment variable in your local shell and re-run: the same code should target a different workspace without any branching.
  • If the wrong channel lights up, the likely cause is a misconfigured publishable key — production workspaces should never be reachable from a non-production environment variable.

Why teams buy Meshes

The workflow stays sellable after launch

  • A leaked dev publishable key cannot trigger production deliveries because it is scoped to the dev workspace only.
  • Retries, dead letters, and replay history live inside each environment workspace — nothing from staging ever shows up in production logs.
  • Because workspaces are the same primitive you use for customers, onboarding a new environment (for example, a preview environment per pull request) is the same operation you already know.

What's next

Keep exploring the same workflow from different angles

Use Case

Multi-Environment Workspaces

See the broader environment-isolation pattern this guide implements.

Open link

Docs

Quickstart

Spin up a workspace and grab a publishable key for each environment.

Open link

Docs

Send Events

See the publishable-key events pattern that lets the same code target different workspaces.

Open link

Docs

Integrations & Rules

Keep rules consistent across environments while letting each workspace own its connections.

Open link

Guide

Let Customers Connect Their Own Slack from the Embed

See the same workspace primitive applied to external customer tenancy.

Open link

Compare

Meshes vs. DIY

Compare per-workspace environment isolation to rolling env flags and branch logic in your own integration code.

Open link

Next stepStart free or keep reading the docs

Give every environment its own workspace

Run dev, staging, and production as their own Meshes workspaces so test events never reach real Slack channels or real customer integrations.

Start freeView documentation