code examples

Sent logo
Sent TeamMay 3, 2025 / code examples / Article

Sending SMS with AWS SNS in Next.js

A step-by-step guide on integrating AWS SNS into a Next.js application using Node.js API routes to send SMS messages.

Developer Guide: Sending SMS with AWS SNS in Next.js using Node.js

This guide provides a step-by-step walkthrough for integrating Amazon Simple Notification Service (SNS) into a Next.js application to send SMS messages using Node.js for the backend logic via API routes.

Project Overview and Goals

What We're Building: We will build a simple Next.js application featuring a backend API endpoint. This endpoint will accept a phone number and a message, then use the AWS SDK for JavaScript (v3) to interact with AWS SNS and send the message as an SMS to the specified number.

Problem Solved: This implementation enables developers to add reliable SMS notification capabilities (like OTPs, alerts, or status updates) to their Next.js applications without managing complex telephony infrastructure. AWS SNS handles the carrier integrations and delivery complexities.

Technologies Used:

  • Next.js: A React framework providing server-side rendering, static site generation, and simplified API route creation. We'll use API routes for our backend logic.
  • Node.js: The runtime environment for our Next.js API route.
  • AWS SDK for JavaScript v3 (@aws-sdk/client-sns): The official AWS SDK used to interact with SNS programmatically.
  • AWS Simple Notification Service (SNS): The managed AWS service that facilitates sending messages, including SMS.
  • AWS Identity and Access Management (IAM): Used to securely grant our application the necessary permissions to publish messages via SNS.

System Architecture:

The data flow is straightforward:

  1. Client Request: A client (e.g., a frontend form, Postman, curl) sends a POST request to our Next.js API endpoint (/api/send-sms) containing the recipient's phone number and the message content.
  2. Next.js API Route: The Node.js code within the API route receives the request.
  3. AWS SDK: The API route uses the @aws-sdk/client-sns library, configured with appropriate IAM credentials, to prepare and send a PublishCommand to AWS SNS.
  4. AWS SNS: SNS receives the command, validates it, and attempts to deliver the SMS message to the specified phone number via downstream carriers.
  5. SMS Delivery: The recipient receives the SMS message on their mobile device.
  6. API Response: The Next.js API route sends a response back to the client indicating success (with a message ID) or failure.

Flow: Client -> Next.js API Route -> AWS SDK -> AWS SNS -> Mobile Network -> Recipient

Prerequisites:

  • Node.js (v18.x or v20.x LTS recommended; v14.x+ required for AWS SDK v3 ES6 modules)
  • npm or yarn package manager
  • An active AWS account
  • Basic familiarity with Next.js and JavaScript/Node.js
  • AWS CLI installed and configured (optional, but helpful for local credential management)

Expected Outcome: By the end of this guide, you will have a functional Next.js API endpoint capable of sending SMS messages via AWS SNS, along with foundational knowledge for error handling, security, and deployment considerations.

1. Setting up the Project

Let's create a new Next.js project and install the necessary dependencies.

  1. Create Next.js App: Open your terminal and run:

    bash
    npx create-next-app@latest sns-sms-app

    Choose your preferred settings when prompted (e.g., TypeScript: No, ESLint: Yes, Tailwind CSS: No, src/ directory: No, App Router: No (or Yes, adapting API route location), import alias: default).

  2. Navigate to Project Directory:

    bash
    cd sns-sms-app
  3. Install Dependencies: We need the AWS SDK for SNS and dotenv for managing environment variables locally.

    bash
    npm install @aws-sdk/client-sns dotenv

    Alternatively using yarn:

    bash
    yarn add @aws-sdk/client-sns dotenv
    • @aws-sdk/client-sns: The modular AWS SDK package for SNS.
    • dotenv: Loads environment variables from a .env file into process.env during development.
  4. Configure Environment Variables: Create a file named .env.local in the root of your project. This file will store your AWS credentials securely during local development. Never commit this file to Git.

    Add the following variables, leaving the values blank for now. We'll obtain these in the AWS Setup step.

    plaintext
    # .env.local
    AWS_ACCESS_KEY_ID=
    AWS_SECRET_ACCESS_KEY=
    AWS_REGION=
    • AWS_ACCESS_KEY_ID: Your AWS IAM user's access key.
    • AWS_SECRET_ACCESS_KEY: Your AWS IAM user's secret key.
    • AWS_REGION: The AWS region where you want to use SNS (e.g., us-east-1). SMS availability varies by region. us-east-1 has broad support.
  5. Update .gitignore: Ensure .env.local is listed in your .gitignore file (Create Next App usually adds .env*.local automatically). If not, add it:

    text
    # .gitignore
    .env*.local
  6. Project Structure: Your basic structure will look like this (assuming pages router):

    sns-sms-app/ ├── pages/ │ ├── api/ │ │ └── # We will create send-sms.js here │ ├── _app.js │ └── index.js ├── public/ ├── styles/ ├── .env.local # Your local secrets (DO NOT COMMIT) ├── .gitignore ├── next.config.js ├── package.json └── README.md

    We will create our API logic inside the pages/api/ directory.

2. AWS Setup (IAM User)

To allow our Next.js application to send SMS via SNS, we need to create an IAM user with specific permissions.

  1. Navigate to IAM: Log in to your AWS Management Console and go to the IAM service.
  2. Create User:
    • Click on Users in the left sidebar, then click Create user.
    • Enter a User name (e.g., nextjs-sns-sender). Do not check ""Provide user access to the AWS Management Console"". Click Next.
    • Select Attach policies directly.
    • Click Create policy. This will open a new tab.
  3. Create IAM Policy:
    • In the new Create policy tab, select the JSON editor.
    • Paste the following policy document. This grants the minimum permission required to publish messages directly to phone numbers via SNS.
      json
      {
          ""Version"": ""2012-10-17"",
          ""Statement"": [
              {
                  ""Sid"": ""AllowSNSDirectPublishSMS"",
                  ""Effect"": ""Allow"",
                  ""Action"": ""sns:Publish"",
                  ""Resource"": ""*""
              }
          ]
      }
      • Explanation:
        • Action: ""sns:Publish"": Allows the user to publish messages.
        • Resource: ""*"": Necessary when publishing directly to phone numbers using the PhoneNumber parameter. If you were publishing only to specific SNS Topics, you would list their ARNs here for tighter security.
    • Click Next.
    • Give the policy a Name (e.g., SNSPublishDirectSMS) and optionally a description. Click Create policy.
  4. Attach Policy & Create User:
    • Go back to the Create user browser tab. Click the refresh button next to Create policy.
    • Search for the policy you just created (SNSPublishDirectSMS).
    • Check the box next to the policy. Click Next.
    • Review the user details and permissions. Click Create user.
  5. Retrieve Access Keys (IMPORTANT):
    • On the confirmation screen, click on the user name you just created (nextjs-sns-sender).
    • Go to the Security credentials tab.
    • Scroll down to Access keys and click Create access key.
    • Select Application running outside AWS (or Command Line Interface if using AWS CLI profile).
    • Click Next.
    • Optionally add a description tag. Click Create access key.
    • CRITICAL: You will now see the Access key ID and Secret access key. Copy both immediately and store them securely. You will not be able to see the Secret access key again after leaving this screen.
    • Paste these values into your .env.local file.
      plaintext
      # .env.local
      AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID_HERE
      AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY_HERE
      AWS_REGION=us-east-1 # Or your chosen supported region
    • Click Done.

3. SNS Client Setup

Let's create a reusable SNS client instance.

  1. Create Library File: Create a directory lib in your project root and add a file snsClient.js inside it.

    bash
    mkdir lib
    touch lib/snsClient.js
  2. Instantiate SNS Client: Add the following code to lib/snsClient.js:

    javascript
    // lib/snsClient.js
    import { SNSClient } from ""@aws-sdk/client-sns"";
    import ""dotenv/config""; // Ensure environment variables are loaded (especially for non-Next.js environments if reused)
    
    // The AWS SDK automatically searches for credentials in the following order:
    // 1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN)
    // 2. Shared credential file (~/.aws/credentials)
    // 3. Shared configuration file (~/.aws/config)
    // 4. EC2 instance profile or ECS container credentials (if running on AWS)
    
    // Ensure your region is set correctly
    const region = process.env.AWS_REGION;
    
    if (!region) {
      console.warn(
        ""AWS_REGION environment variable not set. Defaulting may occur, but explicit setting is recommended.""
      );
      // Optionally throw an error if region is absolutely required:
      // throw new Error(""AWS_REGION environment variable is required."");
    }
    
    const snsClient = new SNSClient({
      region: region,
      // Credentials are automatically sourced from environment variables or shared config.
      // You generally DO NOT need to pass credentials explicitly here if using .env.local or ~/.aws/credentials.
    });
    
    export { snsClient };
    • Explanation:
      • We import the SNSClient from the SDK.
      • We import dotenv/config to ensure .env.local is loaded if this module were ever run outside the Next.js context (Next.js loads .env.local automatically for API routes).
      • We explicitly create the client, passing the region from our environment variables. The SDK handles finding the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from process.env automatically.

4. Building the API Layer

Now, we'll create the Next.js API route that uses our snsClient to send the SMS.

  1. Create API Route File: Create the file pages/api/send-sms.js.

  2. Implement API Logic: Paste the following code into pages/api/send-sms.js:

    javascript
    // pages/api/send-sms.js
    import { snsClient } from ""../../lib/snsClient"";
    import { PublishCommand } from ""@aws-sdk/client-sns"";
    
    // Basic input validation function (customize as needed)
    const validateInput = (phoneNumber, message) => {
      if (!phoneNumber || typeof phoneNumber !== ""string"") {
        return ""Phone number is required and must be a string."";
      }
      // E.164 format regex (basic check; more robust validation might be needed for production edge cases)
      // Allows '+' followed by 1 to 14 digits after the country code digit.
      const phoneRegex = /^\+[1-9]\d{1,14}$/;
      if (!phoneRegex.test(phoneNumber)) {
        return ""Invalid phone number format. Must be E.164 (e.g., +15551234567)."";
      }
      if (!message || typeof message !== ""string"" || message.trim().length === 0) {
        return ""Message is required and cannot be empty."";
      }
      if (message.length > 1600) {
        // SNS automatically handles segmentation but good to have a sanity limit
        return ""Message exceeds maximum length (1600 characters)."";
      }
      return null; // Indicates valid input
    };
    
    export default async function handler(req, res) {
      // Only allow POST requests
      if (req.method !== ""POST"") {
        res.setHeader(""Allow"", [""POST""]);
        return res.status(405).json({
          success: false,
          error: `Method ${req.method} Not Allowed`,
        });
      }
    
      const { phoneNumber, message } = req.body;
    
      // --- Input Validation (Security) ---
      const validationError = validateInput(phoneNumber, message);
      if (validationError) {
        console.warn(""Validation failed:"", validationError);
        return res.status(400).json({ success: false, error: validationError });
      }
    
      // --- Set SMS Type (Optional but Recommended) ---
      // Default without MessageAttributes is Promotional. Transactional is better for OTPs/Alerts.
      // See section 8 for details.
      const messageAttributes = {
        ""AWS.SNS.SMS.SMSType"": {
          DataType: ""String"",
          StringValue: ""Transactional"", // Set to 'Transactional' for high priority (e.g., OTPs)
                                        // Change to 'Promotional' for marketing (lower cost/priority)
        },
        // You can add other attributes like SenderID here if configured
        // ""AWS.SNS.SMS.SenderID"": {
        //   DataType: ""String"",
        //   StringValue: ""MySenderID"", // Your registered Sender ID
        // },
      };
    
      // --- Prepare SNS Publish Command ---
      const params = {
        Message: message,
        PhoneNumber: phoneNumber, // Must be in E.164 format
        MessageAttributes: messageAttributes, // Set SMS type (Transactional recommended for non-marketing)
      };
    
      const command = new PublishCommand(params);
    
      // --- Send SMS via SNS ---
      try {
        const data = await snsClient.send(command);
        console.log(""SMS sent successfully. MessageId:"", data.MessageId);
        return res.status(200).json({ success: true, messageId: data.MessageId });
      } catch (err) {
        console.error(""Error sending SMS via SNS:"", err);
    
        // Provide more specific feedback if possible
        let errorMessage = ""Failed to send SMS."";
        if (err.name === ""InvalidParameterValueException"") {
          errorMessage =
            ""Invalid parameter provided to SNS. Check phone number format (E.164) or message content."";
        } else if (err.name === ""AuthorizationErrorException"") {
          errorMessage = ""Authorization error. Check AWS credentials and IAM permissions."";
        } else if (err.name === ""ThrottlingException"") {
            errorMessage = ""Request throttled by AWS. Please try again later."";
        } else if (err.name === ""InternalErrorException"") {
            errorMessage = ""Internal server error on AWS side. Please try again later."";
        } else if (err.name === ""PhoneNumberOptedOutException"") {
            errorMessage = ""Phone number is opted out of receiving SMS messages."";
        }
        // Add more specific error checks based on potential SNS exceptions
    
        return res
          .status(500)
          .json({ success: false, error: errorMessage, details: err.message }); // Include err.message for detailed debugging if needed
      }
    }
  3. Testing the Endpoint (curl): Make sure your Next.js development server is running (npm run dev or yarn dev).

    Open a new terminal window and run the following curl command, replacing +15551234567 with a valid E.164 formatted phone number (ideally your own for testing) and customizing the message:

    bash
    curl -X POST http://localhost:3000/api/send-sms \
    -H ""Content-Type: application/json"" \
    -d '{
      ""phoneNumber"": ""+15551234567"",
      ""message"": ""Hello from Next.js and AWS SNS! This is a test message.""
    }'
    • Expected Request Body (JSON):
      json
      {
        ""phoneNumber"": ""+1XXXXXXXXXX"",
        ""message"": ""Your message content""
      }
    • Expected Success Response (JSON):
      json
      {
        ""success"": true,
        ""messageId"": ""xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx""
      }
      You should receive the SMS shortly after seeing this response.
    • Expected Error Response (JSON, e.g., validation):
      json
      {
        ""success"": false,
        ""error"": ""Invalid phone number format. Must be E.164 (e.g., +15551234567).""
      }

5. Implementing Error Handling and Logging

Our API route already includes basic error handling and logging:

  • try...catch Block: Wraps the snsClient.send() call to catch exceptions during the SNS interaction.
  • Input Validation: Prevents invalid data from reaching the SNS publish command.
  • Console Logging:
    • console.error is used to log failures on the server-side (visible in your terminal during development or in Vercel/server logs when deployed).
    • console.log confirms successful sending.
    • console.warn logs validation failures.
  • Specific Error Messages: The catch block attempts to identify common SNS error types (err.name) to provide more user-friendly feedback in the API response, while still logging the full error details server-side.
  • HTTP Status Codes: Uses appropriate codes (200, 400, 405, 500) to signal the outcome.

Further Enhancements (Beyond Basic):

  • Structured Logging: For production, use libraries like Pino or Winston for structured JSON logs, making them easier to parse and analyze in log aggregation tools.
  • Error Tracking Services: Integrate services like Sentry or Datadog to capture, aggregate, and alert on application errors.
  • Retry Mechanisms: While the AWS SDK might handle some transient network retries, for critical messages requiring guaranteed delivery attempts, consider implementing a queue-based system (like AWS SQS) with exponential backoff logic. The API route would push the message details to the queue, and a separate worker process would handle dequeuing, sending via SNS, and implementing retries on failure. This is more complex and usually reserved for high-throughput or high-reliability scenarios.

6. Database Schema and Data Layer

This specific guide focuses solely on sending an SMS via an API call and does not require a database.

If your application needed to store message history, user preferences, or associate SMS messages with specific users or events, you would typically:

  1. Choose a Database: PostgreSQL, MySQL, MongoDB, DynamoDB, etc.
  2. Design Schema: Define tables/collections (e.g., users, sms_messages with columns like message_id, recipient_phone, status, sent_at, user_id, content). Use an Entity Relationship Diagram (ERD) tool to visualize relationships.
  3. Implement Data Layer: Use an ORM (like Prisma, TypeORM, Sequelize) or a database client library to interact with the database. Implement functions like saveMessageRecord, updateMessageStatus.
  4. Migrations: Use the ORM's migration tools (prisma migrate dev, sequelize db:migrate) to manage schema changes.
  5. Integration: Call data layer functions from your API route before or after sending the SMS to record the attempt and outcome.

This is beyond the scope of basic SNS sending but is a common next step in real-world applications.

7. Adding Security Features

Security is paramount, especially when dealing with external services and potentially user-provided data.

  • Input Validation: (Implemented in API route) Crucial to prevent malformed requests and potential injection attacks (though less direct risk for SNS message content itself compared to SQL injection). Ensure phone numbers match E.164 and messages have reasonable length/content. Sanitize message content if it originates directly from untrusted user input.
  • API Key Protection: (Implemented via .env.local and Environment Variables) Never hardcode AWS credentials in your source code. Use environment variables and ensure .env*.local files are in .gitignore. Use your deployment platform's secret management features (e.g., Vercel Environment Variables, AWS Secrets Manager).
  • IAM Least Privilege: (Implemented via IAM Policy) The IAM user nextjs-sns-sender only has sns:Publish permission, limiting potential damage if credentials were compromised. Avoid using root account keys.
  • Rate Limiting: (Not Implemented - Recommended) Protect your API endpoint from abuse and control costs.
    • Implement using libraries like rate-limiter-flexible or express-rate-limit (if using Express middleware).
    • Leverage platform features (e.g., Vercel's rate limiting).
    • Configure reasonable limits (e.g., 5 requests per minute per IP address).
  • Authentication/Authorization: If the API endpoint should only be accessible by logged-in users or specific services, implement authentication (e.g., using NextAuth.js, JWT, or API keys for service-to-service communication) and authorization checks within the API route before processing the request.
  • HTTPS: Ensure your Next.js application is served over HTTPS (handled automatically by platforms like Vercel).

8. Handling Special Cases

  • E.164 Phone Number Format: (Handled via Validation) SNS strictly requires the E.164 format (+ followed by country code and number, no spaces or dashes, e.g., +12125551234, +442071234567). Your frontend or backend must ensure numbers are in this format before calling the API.
  • SMS Type (Transactional vs. Promotional): (Handled via MessageAttributes)
    • Promotional: (Default if MessageAttributes is omitted) Optimized for cost, lower delivery priority, may be blocked by DND (Do Not Disturb) registries. Suitable for marketing.
    • Transactional: (Set in our example code) Optimized for reliability, higher delivery priority, can often bypass DND. Use for critical messages like OTPs, alerts, order confirmations. Slightly higher cost per message.
    • Modify the StringValue in the messageAttributes object in pages/api/send-sms.js based on your use case.
  • Opt-Out Handling: Users can reply ""STOP"" to opt-out of receiving messages. Sending to an opted-out number will fail (SNS returns PhoneNumberOptedOutException).
    • You can check if a number is opted out before sending using the CheckIfPhoneNumberIsOptedOutCommand from @aws-sdk/client-sns. This adds latency but can prevent errors and save cost. See AWS SDK documentation for usage. Our basic error handling catches the exception after the send attempt.
  • Character Limits & Encoding: Standard SMS messages have limits (160 characters for GSM-7 encoding, 70 for UCS-2 used for non-Latin characters). SNS automatically handles segmentation for longer messages (sending multiple linked SMS), but each segment is billed separately. Be mindful of message length for cost.
  • Sender ID: By default, messages may come from a shared short code or random long code number depending on the destination country. You can request dedicated short codes or long codes, or register an Alphanumeric Sender ID (where supported) through the AWS console for branding (subject to country regulations and additional cost). See ""Pinpoint SMS and voice settings"" in the AWS console. If registered, you can specify it via MessageAttributes.

9. Implementing Performance Optimizations

For basic, low-volume SMS sending, performance is usually not a major concern. The key points are:

  • Asynchronous Operations: The await snsClient.send(command) call is asynchronous, meaning your Node.js process isn't blocked while waiting for SNS. This allows the API route to handle other requests efficiently.
  • Client Reuse: We instantiate the snsClient once (lib/snsClient.js) and reuse it across API requests, avoiding the overhead of creating a new client for every call.
  • Caching: Not typically applicable for the sending action itself.
  • High Throughput: If you need to send a very large volume of SMS messages quickly, sending them sequentially from a single API route instance can become a bottleneck. The recommended pattern is:
    1. API route receives request(s).
    2. API route pushes message details (recipient, content) onto a queue (e.g., AWS SQS).
    3. A separate backend worker process (e.g., an AWS Lambda function triggered by SQS, or a dedicated Node.js service) reads messages from the queue (potentially in batches) and calls snsClient.send() for each. This decouples sending from the initial request and enables parallel processing.

10. Adding Monitoring, Observability, and Analytics

Monitoring is essential to understand if your SMS sending is working correctly and cost-effectively.

  • AWS CloudWatch Metrics: SNS automatically publishes metrics to CloudWatch in the region you're using. Key metrics include:
    • NumberOfMessagesPublished: Successful requests to the SNS API.
    • NumberOfNotificationsDelivered: Successful deliveries to the carrier (doesn't guarantee final device delivery).
    • NumberOfNotificationsFailed: Deliveries that failed (e.g., invalid number, opted-out, carrier block).
    • SMSMonthToDateSpentUSD: Your spending.
    • Create CloudWatch Alarms on these metrics (e.g., alert if NumberOfNotificationsFailed spikes, or if SMSMonthToDateSpentUSD exceeds a budget).
  • AWS CloudWatch Logs: Enable delivery status logging in your SNS settings (Account level -> Text messaging (SMS) -> Edit -> Delivery status logging). This provides detailed logs for each message attempt, including success/failure reasons, message IDs, and pricing, sent to a CloudWatch Log Group you specify. This is invaluable for troubleshooting specific delivery issues.
  • Application Logs: (Implemented via console.log/console.error) Your Next.js API route logs provide context about requests entering your system and any errors occurring before or during the snsClient.send() call. Ensure these logs are captured by your deployment platform (Vercel, AWS, etc.).
  • Health Checks: Implement a simple health check endpoint (e.g., /api/health) in your Next.js app that returns a 200 OK status. Use monitoring services to ping this endpoint regularly to ensure your application is responsive.
  • Dashboards: Create a CloudWatch Dashboard visualizing the key SNS metrics (NumberOfNotificationsDelivered, NumberOfNotificationsFailed, SMSMonthToDateSpentUSD) alongside relevant application metrics.

11. Troubleshooting and Caveats

Common issues when sending SMS with SNS:

  • AuthorizationErrorException: Almost always an IAM permissions issue or incorrect/missing AWS credentials.
    • Verify the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in your environment variables are correct and belong to the IAM user (nextjs-sns-sender).
    • Ensure the SNSPublishDirectSMS policy (or equivalent) is attached to the user and has ""Action"": ""sns:Publish"", ""Resource"": ""*"".
    • Check that the AWS_REGION environment variable matches the region where you expect SNS to operate.
  • InvalidParameterValueException: Usually related to the PhoneNumber format.
    • Ensure the number starts with + and includes the country code (E.164 format). No spaces, dashes, or parentheses.
    • Check that the Message content is valid (e.g., not excessively long if you added strict checks).
  • SMS Not Received (but API returns success):
    • SNS Sandbox: New AWS accounts are placed in the SNS sandbox, which limits sending to verified phone numbers only and has low sending quotas. Verify destination numbers in the SNS console or request to move your account out of the sandbox via an AWS support case (Pinpoint SMS and voice settings -> Request production access). This is a very common issue for new users.
    • Opted-Out Number: The recipient may have previously replied STOP. The API call will now likely fail with PhoneNumberOptedOutException. Check delivery status logs if enabled.
    • Invalid/Inactive Number: The phone number might be incorrect or no longer in service.
    • Carrier Filtering: Mobile carriers may sometimes filter messages as spam, especially if coming from shared numbers or containing certain keywords. Using Transactional SMS type, dedicated numbers, or registered Sender IDs can help.
    • Region Support: Ensure the destination country is supported for SMS sending from your chosen AWS region.
    • Check CloudWatch Delivery Status Logs: If enabled, these provide the most detail on delivery failures after SNS accepts the message.
  • ThrottlingException: You're exceeding SNS sending limits for your account or region. Slow down requests or request a limit increase via AWS support. Using a queue can help smooth out traffic.
  • Spending Limit Exceeded: Your account has a monthly SMS spending limit configured in SNS. Check and potentially increase it in the SNS console (Text messaging (SMS) settings).
  • Region Mismatch: Ensure the AWS_REGION environment variable used by the SDK client matches the region where you configured any SNS settings (like spending limits or Sender IDs) and where your IAM user operates (though IAM is global, keys are generated globally). us-east-1 is often a safe default for broad SMS support.

12. Deployment and CI/CD

Deploying your Next.js application requires ensuring your AWS credentials and region are securely available in the production environment.

Key Steps:

  1. Environment Variables: Do not commit your .env.local file. Use your deployment platform's interface to set the required environment variables:
    • AWS_ACCESS_KEY_ID
    • AWS_SECRET_ACCESS_KEY
    • AWS_REGION
    • Example (Vercel): Go to your Project Settings -> Environment Variables. Add each variable, ensuring they are set for the ""Production"" environment (and ""Preview""/""Development"" if needed). Keep them ""Secret"".
    • Example (AWS Amplify/EC2/Lambda): Use the service's environment variable configuration, AWS Secrets Manager, or Parameter Store.
  2. Build Process: Your standard Next.js build process (npm run build) remains the same.
  3. Deployment: Deploy using your platform's CLI (vercel deploy --prod) or Git-based deployment workflow. The deployed application (specifically the API route) will pick up the environment variables set in the platform.
  4. CI/CD Pipeline:
    • Use standard CI/CD tools (GitHub Actions, GitLab CI, Jenkins).
    • The pipeline needs secure access to deploy to your platform.
    • Crucially, ensure AWS secrets are handled securely, often using the CI/CD platform's secrets management features, injecting them only during the deployment step, not during build if possible.
  5. Rollback: Familiarize yourself with your deployment platform's rollback procedures (e.g., Vercel's previous deployments) in case a deployment introduces issues.

13. Verification and Testing

Thorough testing ensures your SMS functionality works as expected.

  1. Manual Verification:
    • Deploy your application to a preview or production environment.
    • Use curl or Postman (as shown in Section 4) to hit your deployed API endpoint (https://your-app-domain.com/api/send-sms).
    • Use your own phone number (or a colleague's) as the recipient (ensure it's verified if still in the SNS Sandbox).
    • Verify:
      • You receive a 200 OK success response with a messageId.
      • The SMS message arrives on the phone.
      • The message content is correct.
    • Test edge cases: invalid phone number format, empty message, excessively long message. Verify you get the expected 400 Bad Request or 500 Internal Server Error responses with appropriate error messages.
  2. Check CloudWatch Metrics/Logs:
    • After sending test messages, go to the CloudWatch console in your selected AWS region.
    • Check SNS metrics (NumberOfMessagesPublished, NumberOfNotificationsDelivered, NumberOfNotificationsFailed).
    • If delivery status logging is enabled, check the corresponding Log Group for detailed success/failure records.
  3. Automated Testing (Recommended):
    • API Integration Tests: Use tools like Jest or Vitest with supertest to make actual HTTP requests to your local running dev server's API endpoint. You'd likely mock the snsClient.send call to avoid sending real SMS during tests.

Frequently Asked Questions

How to send SMS messages with Next.js?

You can send SMS messages with Next.js by creating a backend API endpoint using API routes and integrating with AWS SNS. This endpoint handles requests containing the phone number and message, then leverages the AWS SDK for JavaScript to send the SMS via SNS.

What is AWS SNS used for in Next.js?

AWS SNS (Simple Notification Service) is used in Next.js applications to manage the sending of SMS messages. It handles carrier integration and delivery complexities, allowing developers to add SMS functionality without managing telephony infrastructure.

Why use AWS SDK for JavaScript in Next.js SMS?

The AWS SDK for JavaScript (specifically the `@aws-sdk/client-sns` package) provides the necessary functions to interact with AWS SNS directly from your Next.js application's backend code. This simplifies sending SMS messages programmatically.

How to set up AWS credentials for Next.js SNS?

Create an IAM user in your AWS account with the 'sns:Publish' permission. Generate access keys for this user and store them securely in a `.env.local` file in your Next.js project. Never commit this file to version control.

What is the correct phone number format for AWS SNS?

AWS SNS requires phone numbers to be in E.164 format. This is a standardized international format that includes a '+' sign followed by the country code and phone number, without any spaces or special characters (e.g., +15551234567).

How to handle different SMS message types with SNS?

You can specify the SMS type (Transactional or Promotional) using the `MessageAttributes` parameter when sending a message with the AWS SDK. Transactional is recommended for critical messages like OTPs, while Promotional is better for marketing messages.

When should I use transactional vs promotional SMS?

Use Transactional SMS for high-priority alerts and OTPs as they have higher delivery priority and can bypass DND. Use Promotional SMS for marketing messages as they are cost-effective but have lower priority.

Can I send SMS to international numbers with AWS SNS?

Yes, AWS SNS supports sending SMS to international numbers. Ensure the phone numbers are in E.164 format, including the country code, and verify that the destination country is supported by SNS in your chosen AWS region.

How to troubleshoot AWS SNS authorization errors?

Authorization errors usually mean incorrect AWS credentials or insufficient IAM permissions. Double-check your `.env.local` file, ensuring the correct access keys and region are used. Also, verify the IAM user has the necessary 'sns:Publish' permission.

What to do if SMS is not received but API returns success?

If the API call succeeds but the SMS is not received, check if your AWS account is in the SNS sandbox. If so, verify the recipient number in the SNS console or request sandbox removal. Other reasons might be an opted-out number, carrier filtering, incorrect number, or destination country not being supported by SNS from your selected region.

How to handle SMS opt-outs in Next.js with AWS SNS?

Users can opt out by replying "STOP". You can proactively check if a number has opted out using the `CheckIfPhoneNumberIsOptedOutCommand` before sending. The API will also return an error if you try sending to an opted-out number.

How to improve SMS sending performance in Next.js?

For high-throughput scenarios, use a queue system like AWS SQS. The API route adds messages to the queue, and a separate worker process consumes messages from the queue and sends them via SNS, enabling parallel processing.

What are best practices for monitoring AWS SNS?

Monitor CloudWatch metrics like `NumberOfMessagesPublished`, `NumberOfNotificationsDelivered`, and `NumberOfNotificationsFailed`. Enable delivery status logging in SNS for detailed logs on message delivery attempts. Set CloudWatch alarms to alert on failures or cost overruns.

How to securely deploy Next.js app with AWS SNS integration?

Store AWS credentials as environment variables in your deployment platform (e.g., Vercel, AWS Amplify), not in your code. Never commit `.env.local` to version control. Use the platform's secrets management features during CI/CD.