Providers Overview
FORGE uses a provider-based architecture to integrate with external services. Providers are pluggable implementations of common service categories such as SMS, email, storage, and payments. Each category defines a shared trait (interface) and supports multiple driver implementations that can be swapped at runtime.
Architecture
The provider system follows a trait-factory pattern:
┌─────────────────────────────────────────────────────────┐
│ Provider System │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ │
│ │ Trait │ Common interface (send, store, etc.) │
│ │ (Interface) │ │
│ └──────┬──────┘ │
│ │ │
│ ┌─────┼──────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────────┐ ┌────────┐ │
│ │Twilio│ │ Unifonic │ │ Vonage │ Driver implementations│
│ └──────┘ └──────────┘ └────────┘ │
│ │ │ │ │
│ └──────────┼─────────────┘ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Factory │ Creates the right driver at │
│ │ │ runtime from configuration │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘How It Works
- Trait -- Defines the contract that all drivers must implement (e.g.,
SmsProvider::send()) - Drivers -- Concrete implementations for specific services (e.g., Twilio, SendGrid, S3)
- Factory -- Reads the configuration and instantiates the correct driver at runtime
This design allows you to switch providers without changing application code. For example, migrating from Twilio to Vonage requires only a configuration change.
Provider Categories
| Category | Trait | Available Drivers | Docs |
|---|---|---|---|
| SMS | SmsProvider | Twilio, Unifonic, Vonage | SMS Providers |
EmailProvider | SMTP, SendGrid, Mailgun, Amazon SES | Email Providers | |
| Storage | StorageProvider | Local, S3 | Storage Providers |
| Payments | PaymentProvider | HyperPay, Checkout.com | Payment Providers |
Configuration
Providers are configured in two places:
1. forge.yaml
The providers section in forge.yaml defines which driver to use for each category:
providers:
sms: twilio
email: smtp
storage: local
payments: hyperpay2. Settings Table
Driver-specific credentials and options are stored in the database settings table, grouped under the provider category:
┌────────────┬───────────────────┬────────────────────────────┐
│ group_name │ key │ value │
├────────────┼───────────────────┼────────────────────────────┤
│ sms │ twilio_account_sid│ ACxxxxxxxxxxxxxxxxxxxxxxxx │
│ sms │ twilio_auth_token │ •••••••••••••••• │
│ sms │ twilio_from_number│ +15551234567 │
│ email │ email_host │ smtp.example.com │
│ email │ email_port │ 587 │
│ storage │ s3_bucket │ my-app-uploads │
└────────────┴───────────────────┴────────────────────────────┘TIP
Credentials are stored as encrypted settings using AES-256-GCM. They are never exposed in plain text through the admin UI or API.
Installing a Provider
Use the FORGE CLI to install a provider driver:
# Install a specific provider driver
forge provider:add sms:twilio
forge provider:add email:sendgrid
forge provider:add storage:s3
forge provider:add payments:hyperpayThe provider:add command:
- Validates the provider type and driver
- Updates
forge.yamlwith the selected driver - Appends the required environment variables to
.envand.env.example- Skips variables that already exist (no duplicates on re-run)
- Creates the files if they don't exist
- Groups variables under a section header (e.g.
# Sms Provider (twilio))
- Displays the required environment variables for reference
TIP
Drivers named log (e.g. sms:log, payment:log) are development-only and require no environment variables. The env file step is skipped entirely for these drivers.
Runtime Provider Creation
The factory reads the current configuration and creates the appropriate driver:
// The factory creates the correct driver based on configuration
let sms = SmsFactory::create(&settings).await?;
sms.send("+1234567890", "Hello from FORGE").await?;
// Switch providers by changing the config -- no code changes needed
let email = EmailFactory::create(&settings).await?;
email.send("user@example.com", "Welcome", "Hello!").await?;
let storage = StorageFactory::create(&settings).await?;
storage.put("uploads/file.pdf", data).await?;WARNING
Ensure all required settings for the selected driver are configured before using the provider. Missing credentials will result in a runtime error when the factory attempts to create the driver.
Creating Custom Providers
FORGE supports creating your own provider implementations. See Custom Providers for a step-by-step guide on implementing and registering a custom driver.