This guide provides a complete walkthrough for building a feature within a Next.js application to send Multimedia Messaging Service (MMS) messages using the Infobip API and their official Node.js SDK. We will create a simple frontend interface to trigger an API route that handles the secure interaction with Infobip.
This approach enables you to add powerful MMS capabilities – like sending images, videos, or audio alongside text – directly from your web application, ideal for notifications, marketing campaigns, or enhanced user communication.
Project Overview and Goals
Goal: To create a Next.js application with a serverless API route that securely sends MMS messages via the Infobip platform.
Problem Solved: Provides a robust, server-side mechanism to send MMS messages without exposing sensitive API credentials on the client-side. Leverages Infobip's infrastructure for reliable message delivery.
Technologies:
- Next.js: React framework for building the frontend UI and API routes (serverless Node.js functions). Chosen for its hybrid rendering capabilities and simplified API creation.
- Node.js: JavaScript runtime environment used by Next.js API routes.
- Infobip: Communications Platform as a Service (CPaaS) provider. We'll use their API and Node.js SDK for sending MMS. Chosen for its specific MMS capabilities and developer tooling.
@infobip-api/sdk
: The official Infobip Node.js SDK for interacting with their API.
Architecture Flow:
- User Browser: Initiates an HTTPS Request to the Next.js Frontend.
- Next.js Frontend: Makes an API Call (
/api/send-mms
) to the Next.js API Route. - Next.js API Route: Uses the Infobip SDK to call the Infobip MMS API.
- Infobip MMS API: Sends the MMS message to the Recipient's Mobile Device.
- Next.js API Route: Returns an API Response to the Next.js Frontend.
- Next.js Frontend: Updates the UI based on the response for the User Browser.
Prerequisites:
- Node.js (v16 or later recommended) and npm/yarn installed.
- An active Infobip account. You can create a free trial account if you don't have one.
- Your Infobip API Key and Base URL (obtained from the Infobip dashboard).
- A publicly accessible URL for the media file you want to send (e.g., an image hosted on cloud storage). Infobip needs to fetch this URL.
- If using a free trial account, you can typically only send messages to the phone number you registered with.
Outcome: A functional Next.js application where a user can input a recipient phone number, a media URL, and text, then click a button to send an MMS message via Infobip.
1. Setting up the Project
Let's initialize a new Next.js project and install the necessary dependencies.
-
Create a new Next.js App: Open your terminal and run the following command. Choose your preferred settings when prompted (e.g., TypeScript: No, ESLint: Yes, Tailwind CSS: No,
src/
directory: No, App Router: Yes, Import alias:@/*
).npx create-next-app@latest infobip-mms-nextjs
-
Navigate into the Project Directory:
cd infobip-mms-nextjs
-
Install Infobip Node.js SDK: This package provides a convenient wrapper around the Infobip API.
npm install @infobip-api/sdk
-
Set up Environment Variables: Create a file named
.env.local
in the root of your project. This file stores sensitive credentials securely and should not be committed to version control.# .env.local INFOBIP_API_KEY=YOUR_INFOBIP_API_KEY INFOBIP_BASE_URL=YOUR_INFOBIP_BASE_URL INFOBIP_SENDER_NUMBER=YOUR_INFOBIP_VIRTUAL_NUMBER # Optional, if you have a specific number
- Replace
YOUR_INFOBIP_API_KEY
andYOUR_INFOBIP_BASE_URL
with the actual values from your Infobip account dashboard (see Section 4 for details). - Replace
YOUR_INFOBIP_VIRTUAL_NUMBER
with a number you've acquired through Infobip if you want to specify the sender ID. If omitted or using a trial account, Infobip might assign a sender number. - Why
.env.local
? Next.js automatically loads variables from this file intoprocess.env
on the server-side (API routes) but not on the client-side, preventing accidental exposure of your API Key.
- Replace
-
Add
.env.local
to.gitignore
: Ensure your.gitignore
file (in the project root) includes.env.local
to prevent committing secrets. It's usually included by default increate-next-app
.# .gitignore # ... other entries .env*.local
2. Implementing the API Route
We'll create a serverless API route within Next.js to handle the logic for sending the MMS message. This keeps your Infobip credentials secure on the server.
-
Create the API Route File: Create the following directory structure and file if it doesn't exist:
app/api/send-mms/route.js
. -
Implement the API Logic: Paste the following code into
app/api/send-mms/route.js
.// app/api/send-mms/route.js import { NextResponse } from 'next/server'; import { Infobip, AuthType } from '@infobip-api/sdk'; // Initialize Infobip client const infobip = new Infobip({ baseUrl: process.env.INFOBIP_BASE_URL, apiKey: process.env.INFOBIP_API_KEY, authType: AuthType.ApiKey, }); export async function POST(request) { console.log('Received request to /api/send-mms'); try { const body = await request.json(); const { to, mediaUrl, text } = body; // --- Input Validation --- if (!to || !mediaUrl || !text) { console.error('Validation Error: Missing required fields'); return NextResponse.json( { success: false, error: 'Missing required fields: to, mediaUrl, text' }, { status: 400 } ); } // Basic phone validation (can be enhanced) const phoneRegex = /^(\+)?\d{10,15}$/; if (!phoneRegex.test(to)) { console.error('Validation Error: Invalid phone number format'); return NextResponse.json( { success: false, error: 'Invalid phone number format. Use E.164 format (e.g., +14155552671).' }, { status: 400 } ); } // Basic URL validation try { new URL(mediaUrl); // Check if mediaUrl is a valid URL format } catch (_) { console.error('Validation Error: Invalid media URL'); return NextResponse.json( { success: false, error: 'Invalid media URL format.' }, { status: 400 } ); } // --- End Input Validation --- const senderNumber = process.env.INFOBIP_SENDER_NUMBER || 'InfoSMS'; // Use configured number or default alpha sender console.log(`Attempting to send MMS to: ${to} from: ${senderNumber}`); console.log(`Media URL: ${mediaUrl}, Text: ${text}`); // --- Call Infobip API --- const response = await infobip.channels.mms.send({ messages: [ { destinations: [{ to: to }], from: senderNumber, content: { mediaUrl: mediaUrl, text: text, }, }, ], }); console.log('Infobip API Response:', JSON.stringify(response.data, null, 2)); // Check Infobip response status (can be more granular based on Infobip docs) if (response.status >= 200 && response.status < 300 && response.data.messages?.[0]?.status?.groupName !== 'REJECTED') { return NextResponse.json({ success: true_ data: response.data }); } else { console.error('Infobip API Error:'_ response.data); return NextResponse.json( { success: false_ error: 'Failed to send MMS via Infobip'_ details: response.data }_ { status: response.status || 500 } // Use Infobip's status or default to 500 ); } } catch (error) { console.error('API Route Error:'_ error); // Distinguish between Infobip SDK errors and other errors if (error.response) { // Error from Infobip API (e.g._ bad request_ auth error) console.error('Infobip API Error Details:'_ error.response.data); return NextResponse.json( { success: false_ error: 'Infobip API request failed'_ details: error.response.data }_ { status: error.response.status || 500 } ); } else { // Other server error (e.g._ network issue_ code bug) return NextResponse.json( { success: false_ error: 'Internal Server Error' }_ { status: 500 } ); } } }
Explanation:
- Import Dependencies:
NextResponse
for sending responses and theInfobip
client andAuthType
from the SDK. - Initialize Client: Creates an
Infobip
instance using the API Key and Base URL from your environment variables.AuthType.ApiKey
specifies the authentication method. POST
Handler: This function handles incoming POST requests to/api/send-mms
.- Parse Request Body: Extracts
to
_mediaUrl
_ andtext
from the incoming JSON request. - Input Validation: Performs basic checks: presence of required fields_ plausible E.164 phone format using regex_ and valid URL format. Returns a
400 Bad Request
if validation fails. Note: The phone regex is basic; for production_ consider a more robust library likelibphonenumber-js
on the backend as well for stricter E.164 validation. - Set Sender: Uses the number from
.env.local
or a default alphanumeric sender ID ('InfoSMS'). Note: Alphanumeric sender IDs might have restrictions depending on the destination country. Using a purchased number is often more reliable for deliverability and branding (see Section 4). - Call Infobip SDK: Uses
infobip.channels.mms.send()
to send the message. The payload structure follows the Infobip API requirements for MMS. Note: SDK methods can change; always refer to the current official@infobip-api/sdk
documentation for the exact method signatures and payload structures. - Log Responses: Logs the request details and the response from the Infobip API for debugging.
- Handle Response: Checks the HTTP status and the message status group from the Infobip response. Returns a success (
200 OK
) or error JSON response (4xx
or5xx
) to the frontend. - Error Handling (
try...catch
): Catches potential errors during the process. It differentiates between errors originating from the Infobip API itself (e.g._ invalid credentials_ malformed request) and other unexpected server errors_ returning appropriate status codes and messages.
- Import Dependencies:
3. Building the Frontend Interface
Now_ let's create a simple React component on a Next.js page to collect user input and trigger our API route.
-
Modify the Home Page: Replace the contents of
app/page.js
with the following code:// app/page.js 'use client'; // Required for useState and event handlers import { useState } from 'react'; import styles from './page.module.css'; // Optional: for basic styling export default function HomePage() { const [to_ setTo] = useState(''); const [mediaUrl_ setMediaUrl] = useState(''); const [text_ setText] = useState(''); const [statusMessage_ setStatusMessage] = useState(''); const [isLoading_ setIsLoading] = useState(false); const handleSubmit = async (event) => { event.preventDefault(); setIsLoading(true); setStatusMessage('Sending MMS...'); try { const response = await fetch('/api/send-mms', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ to, mediaUrl, text }), }); const result = await response.json(); if (response.ok && result.success) { setStatusMessage(`MMS sent successfully! Message ID: ${result.data?.messages?.[0]?.messageId || 'N/A'}`); // Clear form on success setTo(''); setMediaUrl(''); setText(''); } else { console.error('API Error Response:', result); setStatusMessage(`Failed to send MMS: ${result.error || 'Unknown error'}. ${result.details ? JSON.stringify(result.details) : ''}`); } } catch (error) { console.error('Frontend Fetch Error:', error); setStatusMessage(`An error occurred: ${error.message}`); } finally { setIsLoading(false); } }; return ( <main className={styles.main}> <h1>Send Infobip MMS</h1> <form onSubmit={handleSubmit} className={styles.form}> <div className={styles.formGroup}> <label htmlFor=""to"">Recipient Number (E.164):</label> <input type=""tel"" id=""to"" value={to} onChange={(e) => setTo(e.target.value)} placeholder=""+14155552671"" required disabled={isLoading} /> </div> <div className={styles.formGroup}> <label htmlFor=""mediaUrl"">Media URL (Publicly Accessible):</label> <input type=""url"" id=""mediaUrl"" value={mediaUrl} onChange={(e) => setMediaUrl(e.target.value)} placeholder=""https://example.com/image.jpg"" required disabled={isLoading} /> </div> <div className={styles.formGroup}> <label htmlFor=""text"">Message Text:</label> <textarea id=""text"" value={text} onChange={(e) => setText(e.target.value)} rows=""3"" required disabled={isLoading} ></textarea> </div> <button type=""submit"" disabled={isLoading}> {isLoading ? 'Sending...' : 'Send MMS'} </button> </form> {statusMessage && ( <p className={styles.statusMessage}>{statusMessage}</p> )} </main> ); }
-
(Optional) Add Basic Styling: Create a file
app/page.module.css
for some basic layout:/* app/page.module.css */ .main { display: flex; flex-direction: column; align-items: center; padding: 2rem; min-height: 100vh; font-family: sans-serif; } .form { display: flex; flex-direction: column; gap: 1rem; width: 100%; max-width: 400px; margin-top: 1.5rem; } .formGroup { display: flex; flex-direction: column; } .formGroup label { margin-bottom: 0.5rem; font-weight: bold; } .formGroup input, .formGroup textarea { padding: 0.75rem; border: 1px solid #ccc; border-radius: 4px; font-size: 1rem; } .formGroup textarea { resize: vertical; } .form button { padding: 0.75rem 1.5rem; background-color: #0070f3; color: white; border: none; border-radius: 4px; font-size: 1rem; cursor: pointer; transition: background-color 0.2s ease; } .form button:hover:not(:disabled) { background-color: #005bb5; } .form button:disabled { background-color: #ccc; cursor: not-allowed; } .statusMessage { margin-top: 1.5rem; padding: 1rem; border-radius: 4px; background-color: #f0f0f0; border: 1px solid #ddd; width: 100%; max-width: 400px; text-align: center; word-wrap: break-word; }
Explanation:
'use client'
: Marks this component as a Client Component, necessary for using hooks likeuseState
and handling browser events.- State Variables:
useState
manages the input field values (to
,mediaUrl
,text
), loading state (isLoading
), and status messages (statusMessage
). handleSubmit
:- Prevents default form submission.
- Sets loading state and initial status message.
- Uses
fetch
to send aPOST
request to our/api/send-mms
endpoint. - Sends the form data as a JSON string in the request body.
- Parses the JSON response from the API route.
- Updates the
statusMessage
based on success or failure, including the Message ID on success or error details on failure. - Clears the form fields on success.
- Includes error handling for the
fetch
call itself (e.g., network errors). - Resets loading state in the
finally
block.
- Form: Standard HTML form elements bound to the React state variables. The submit button is disabled while the request is in progress.
- Status Display: Renders the
statusMessage
paragraph conditionally.
4. Integrating with Infobip – Getting Credentials
To connect your application to Infobip, you need your API Key and Base URL.
- Log in to Infobip: Go to the Infobip Portal and log in.
- Find API Key:
- Navigate to the homepage/dashboard after login.
- Look for a section usually titled ""API Keys"" or similar. You might see a default key or have the option to create a new one.
- Copy the API Key. This is the value for
INFOBIP_API_KEY
in your.env.local
file.
- Find Base URL:
- On the same dashboard or in the API documentation section, find your personalized Base URL. It often looks like
xxxxx.api.infobip.com
. - Copy this URL. This is the value for
INFOBIP_BASE_URL
in your.env.local
file.
- On the same dashboard or in the API documentation section, find your personalized Base URL. It often looks like
- Get a Sender Number (Optional but Recommended):
- Navigate to the ""Numbers"" section in the Infobip portal.
- Acquire a virtual number capable of sending MMS in the regions you target.
- Copy this number (usually in E.164 format, e.g.,
+14155550100
). This is the value forINFOBIP_SENDER_NUMBER
in your.env.local
file. - Why use a purchased number? Using a dedicated virtual number generally improves message deliverability, helps avoid carrier filtering associated with shared or generic IDs, builds brand recognition, and may be required for certain features or regions.
- Secure Storage: Ensure these values are only placed in your
.env.local
file and that this file is listed in your.gitignore
. Never commit these credentials directly into your code.
5. Error Handling and Logging
Our API route includes basic error handling, but here's how to think about it more broadly:
-
API Route (
route.js
):- Input Validation: Catches invalid request formats early (missing fields, bad phone/URL format). Returns
400 Bad Request
. - Infobip SDK Errors: The
try...catch
block specifically catches errors thrown by the@infobip-api/sdk
. These often contain detailed error information from Infobip (like authentication failure, invalid destination number, insufficient funds) inerror.response.data
and a status code inerror.response.status
. We log this detail server-side and return a relevant status code (4xx
or5xx
) with a generic error message plus details to the client. - Infobip Success with Failure Status: We check
response.data.messages[0].status.groupName
because Infobip might return a200 OK
HTTP status but indicate message rejection within the payload (e.g.,REJECTED
). - General Server Errors: Catches any other unexpected errors (network issues connecting to Infobip, internal code bugs) and returns a
500 Internal Server Error
. - Logging:
console.log
andconsole.error
are used for basic logging. For production, consider structured logging libraries likepino
orwinston
to format logs better and send them to dedicated logging services (e.g., Datadog, Logtail, Sentry).
- Input Validation: Catches invalid request formats early (missing fields, bad phone/URL format). Returns
-
Frontend (
page.js
):- Fetch Errors: Catches network errors preventing the request from reaching the API route.
- API Response Handling: Checks
response.ok
and thesuccess
flag in the JSON payload to determine if the API call itself succeeded. Displays user-friendly messages based on the API response, including error details if provided.
-
Retry Mechanisms: For transient errors (e.g., temporary network issues, Infobip rate limits - often indicated by
429
or5xx
status codes), you could implement a retry strategy in the API route. This typically involves catching specific error types/codes and retrying theinfobip.channels.mms.send
call after a delay, often with exponential backoff (e.g., wait 1s, then 2s, then 4s). Libraries likeasync-retry
can simplify this. However, be cautious: do not retry errors that indicate permanent failure (e.g., invalid number, insufficient funds, message rejected due to content,4xx
errors other than rate limits) to avoid duplicate sends or unnecessary cost. Identify retryable error codes based on Infobip's documentation or API responses.
6. Database Schema and Data Layer (Not Applicable Here)
This specific guide focuses solely on the action of sending an MMS and does not require a database.
If you were building a larger application (e.g., storing message history, user preferences, campaign data), you would:
- Choose a Database: PostgreSQL, MySQL, MongoDB, etc.
- Define Schema: Create tables/collections (e.g.,
messages
table with columns likeinfobip_message_id
,recipient_number
,sender_number
,status
,media_url
,text_content
,sent_at
,updated_at
). Use an ORM like Prisma or Sequelize for easier database interaction and migrations. - Implement Data Access: Create functions or repository classes in your backend (potentially separate from the API route handler) to insert/update message records before/after calling the Infobip API.
- Migrations: Use the ORM's migration tools (
prisma migrate dev
,sequelize db:migrate
) to manage schema changes.
7. Adding Security Features
Security is paramount, especially when handling API keys and user data.
- API Key Security:
- Server-Side Only: The API Key is stored in
.env.local
and only accessed within the server-side API route. It's never exposed to the client browser. .gitignore
: Ensure.env.local
is in.gitignore
.- Environment Variables in Deployment: Use your hosting provider's mechanism for securely managing environment variables (e.g., Vercel Environment Variables, AWS Secrets Manager).
- Server-Side Only: The API Key is stored in
- Input Validation and Sanitization:
- The API route performs basic validation (required fields, phone number format using regex, URL format check).
- For production, consider more robust validation libraries (e.g.,
zod
,joi
) to define schemas for expected request bodies. - While not directly applicable here as we aren't storing text long-term or rendering it as HTML, always sanitize user input if it's ever displayed back or stored, to prevent XSS attacks.
- Rate Limiting:
- Protect your API route from abuse. Implement rate limiting based on IP address or user session (if authentication is added).
- Hosting platforms like Vercel offer built-in rate limiting.
- Alternatively, use middleware with libraries like
rate-limiter-flexible
orexpress-rate-limit
(if using a custom Node/Express server).
- Authentication/Authorization (Beyond this guide): If only specific logged-in users should send MMS, implement authentication (e.g., NextAuth.js, Clerk) and check user permissions within the API route before proceeding.
- HTTPS: Next.js development server and platforms like Vercel use HTTPS by default, encrypting data in transit. Ensure this is maintained in production.
8. Handling Special Cases
- Phone Number Formatting: Infobip expects numbers in E.164 format (e.g.,
+14155552671
). The frontend could include a library likelibphonenumber-js
for more robust parsing and validation before sending to the backend. The backend validation provides a safety net. - Media URL Accessibility: The
mediaUrl
must be publicly accessible without authentication for Infobip's servers to fetch it. If using private storage (like AWS S3), generate a pre-signed URL with a short expiry time just before calling the Infobip API. - Media File Types/Size: Infobip has limitations on supported media types (e.g., JPEG, PNG, GIF, MP3, MP4) and file sizes. Refer to the official Infobip MMS documentation for specifics. Handle potential errors if an unsupported type or oversized file is provided.
- Character Limits: While MMS is less restrictive than SMS, there might still be practical limits on text length depending on carriers. Keep text concise.
- International Sending: Be aware of country-specific regulations and potential differences in sender ID support (alphanumeric vs. numeric). Test thoroughly if sending internationally.
- Delivery Reports (Webhooks): For production, set up Infobip webhooks to receive real-time delivery status updates (e.g., delivered, failed, rejected) for sent messages. This requires creating another API endpoint in your Next.js app to receive these webhook POST requests from Infobip and update your message status accordingly (likely in a database).
9. Performance Optimizations (Limited Scope Here)
For this specific function, performance is primarily dependent on the Infobip API's response time.
- API Route Performance: Next.js API routes on platforms like Vercel are generally performant serverless functions. Ensure your validation logic is efficient.
- SDK Initialization: The Infobip client is initialized once when the API route module loads, which is efficient.
- Frontend: Standard React/Next.js optimizations apply (memoization, code splitting - handled by Next.js). The main wait time for the user is the network roundtrip to your API route and then to Infobip.
- Caching: Caching is not directly applicable to the sending action itself.
If sending MMS messages becomes a bottleneck in a high-traffic application:
- Asynchronous Processing: Instead of waiting for the Infobip API call in the API route, you could push the send request into a message queue (e.g., Redis Queue, RabbitMQ, AWS SQS) and have a separate background worker process the queue and call Infobip. The API route would return an immediate ""accepted"" response to the user. This adds complexity but improves responsiveness.
10. Monitoring, Observability, and Analytics
- Logging: As mentioned in Section 5, use structured logging and send logs to a central service for analysis and alerting (e.g., alert on a spike in
5xx
errors from the API route). - Error Tracking: Integrate services like Sentry or Bugsnag to capture and aggregate errors occurring in both the frontend and the API route.
- Health Checks: Create a simple health check endpoint (e.g.,
/api/health
) that returns200 OK
if the basic application is running. Monitoring services can ping this. - Performance Metrics: Hosting platforms (Vercel, Netlify) often provide basic metrics like function duration, invocation count, and error rates for API routes.
- Infobip Analytics: Utilize the analytics and reporting features within the Infobip portal to track message delivery rates, costs, and trends. Correlate
messageId
orbulkId
from the API response with Infobip reports. - Custom Dashboards: If using a database to store message status, build dashboards (e.g., using Grafana, Retool, or your logging platform's tools) to visualize send volume, success rates by country/carrier, error types, etc.
11. Troubleshooting and Caveats
- Error: Invalid API Key/Base URL:
- Symptom: API route returns
401 Unauthorized
or similar authentication errors. Logs show Infobip API error related to credentials. - Solution: Double-check
INFOBIP_API_KEY
andINFOBIP_BASE_URL
in your.env.local
and ensure they are correctly configured in your deployment environment. Verify the key is active in the Infobip portal.
- Symptom: API route returns
- Error: Invalid Destination Number:
- Symptom: API route returns an error (
400 Bad Request
or similar), Infobip response details indicate an invalid 'to' number. - Solution: Ensure the number is in the correct E.164 format (including
+
and country code). Verify the number is valid and capable of receiving MMS. If using a trial account, ensure it's the registered number.
- Symptom: API route returns an error (
- Error: Media URL Not Accessible / Invalid:
- Symptom: Message fails to send, Infobip logs/webhooks might indicate a media fetching error.
- Solution: Verify the
mediaUrl
is publicly accessible (try opening it in an incognito browser window). Ensure it points directly to the media file, not an HTML page. Check Infobip's supported file types and size limits.
- Error: Insufficient Funds (Paid Accounts):
- Symptom: Infobip API returns an error related to account balance.
- Solution: Check your account balance in the Infobip portal.
- Message Sent (API Success) but Not Received:
- Check Infobip Logs/Analytics: Use the
messageId
returned by the API to track the message status in the Infobip portal. Look for detailed delivery reports or error codes (e.g., carrier rejection, blocked number). - Check Sender ID: Ensure the
from
number or sender ID is correctly configured and permitted for the destination country/carrier. - Carrier Issues: Temporary carrier delays or filtering can occur.
- Trial Account Limitation: Remember the restriction of sending only to the registered number on trial accounts.
- Check Infobip Logs/Analytics: Use the
- Environment Variables Not Loaded:
- Symptom:
process.env.INFOBIP_API_KEY
isundefined
in the API route. Application crashes or fails authentication. - Solution: Ensure the file is named exactly
.env.local
. Restart the Next.js development server (npm run dev
) after creating or modifying the file. Verify environment variables are correctly set in your deployment environment.
- Symptom:
- Caveat: MMS Costs: MMS messages are typically more expensive than SMS. Monitor costs in the Infobip portal.
- Caveat: Regional Regulations: MMS sending is subject to local laws and carrier rules (e.g., content restrictions, opt-in requirements). Ensure compliance.
12. Deployment and CI/CD
Deploying a Next.js application is typically straightforward.
Deployment Platforms (e.g., Vercel, Netlify):
- Connect Git Repository: Link your GitHub, GitLab, or Bitbucket repository to the platform.
- Configure Build Settings: Usually auto-detected for Next.js. Default settings are often sufficient.
- Set Environment Variables: Crucially, add
INFOBIP_API_KEY
,INFOBIP_BASE_URL
, andINFOBIP_SENDER_NUMBER
(if used) to the platform's environment variable settings (usually found under Project Settings > Environment Variables). Mark them as sensitive if the option exists. Do not commit.env.local
. - Deploy: Trigger a deployment. The platform will build your Next.js app and deploy the frontend and API routes.
CI/CD Pipeline (e.g., GitHub Actions):
- Workflow File: Create a
.github/workflows/deploy.yml
file. - Trigger: Define triggers (e.g.,
on: push: branches: [ main ]
). - Jobs:
- Checkout Code: Use
actions/checkout@v3
. - Set up Node.js: Use
actions/setup-node@v3
. - Install Dependencies: Run
npm ci
oryarn install --frozen-lockfile
. - Build: Run
npm run build
. - Deploy: Use a platform-specific action (e.g., Vercel CLI Action, Netlify CLI Action) or standard deployment tools (e.g.,
rsync
,scp
, Docker push) depending on your hosting.
- Checkout Code: Use
- Secrets: Store
INFOBIP_API_KEY
,INFOBIP_BASE_URL
, etc., as encrypted secrets in your GitHub repository settings (Settings > Secrets and variables > Actions) and reference them in your workflow file using${{ secrets.YOUR_SECRET_NAME }}
. Inject these into your deployment step as environment variables.
Rollback: Deployment platforms usually offer easy rollback capabilities to previous successful deployments through their UI or CLI. CI/CD pipelines can be configured to trigger rollbacks on failure or manually.