This guide provides a complete walkthrough for building a simple Node.js application using the Express framework to send SMS messages via the Vonage SMS API. We'll cover everything from project setup and configuration to implementation, error handling, and testing.
By the end of this guide, you will have a functional Express API endpoint that accepts a phone number and message, sending the message as an SMS using your Vonage account. This serves as a foundational building block for applications requiring SMS notifications, alerts, or basic communication features.
Project Overview and Goals
What We're Building:
A minimalist Node.js REST API with a single endpoint (/send-sms
). This endpoint will accept a POST request containing a destination phone number and a message body. Upon receiving the request, the API will use the Vonage API to dispatch an SMS message to the specified recipient.
Problem Solved:
Provides a straightforward, server-side mechanism to programmatically send SMS messages, decoupling the SMS sending logic from other parts of an application or system.
Technologies Used:
- Node.js: A JavaScript runtime environment for executing server-side code. Chosen for its asynchronous nature, large ecosystem (npm), and suitability for I/O-bound tasks like API interactions.
- Express.js: A minimal and flexible Node.js web application framework. Chosen for its simplicity in setting up routes and handling HTTP requests, making it ideal for building APIs quickly.
- Vonage SMS API: A service provided by Vonage for sending and receiving SMS messages globally. Chosen for its reliability and developer-friendly SDK.
@vonage/server-sdk
: The official Vonage Node.js SDK for interacting with their APIs (v3 used in examples).dotenv
: A module to load environment variables from a.env
file intoprocess.env
. Used for securely managing API credentials outside of the codebase.
System Architecture:
graph LR
A[Client / API Consumer] -- POST /send-sms --> B(Node.js / Express API);
B -- vonage.sms.send() --> C(Vonage SMS API);
C -- SMS Network --> D(Recipient's Phone);
C -- Response --> B;
B -- JSON Response --> A;
Prerequisites:
- Node.js and npm: Installed on your development machine. (Download Node.js)
- Vonage API Account: A free or paid account is required. (Sign up for Vonage)
- Vonage API Key and Secret: Found in your Vonage Dashboard.
- Vonage Phone Number: A virtual number rented from Vonage or the ability to add verified test numbers (for trial accounts).
- Basic Command Line/Terminal Knowledge: Familiarity with navigating directories and running commands.
- (Optional) API Testing Tool: Such as Postman or
curl
for testing the endpoint.
1. Setting up the Project
Let's initialize our Node.js project and install the necessary dependencies.
-
Create Project Directory: Open your terminal or command prompt and create a new directory for the project, then navigate into it.
mkdir vonage-sms-guide cd vonage-sms-guide
-
Initialize Node.js Project: This command creates a
package.json
file, which tracks project metadata and dependencies. The-y
flag accepts the default settings.npm init -y
-
Install Dependencies: We need Express for the web server, the Vonage SDK to interact with their API, and
dotenv
to manage environment variables.npm install express @vonage/server-sdk dotenv
Note: This installs the latest stable versions. Check compatibility if needed.
-
Enable ES Modules (Optional but Recommended): Using ES Module syntax (
import
/export
) is modern practice. Open yourpackage.json
file and add the following line at the top level:{ ""name"": ""vonage-sms-guide"", ""version"": ""1.0.0"", ""description"": """", ""main"": ""index.js"", ""type"": ""module"", ""scripts"": { ""start"": ""node index.js"", ""test"": ""echo \""Error: no test specified\"" && exit 1"" }, ""keywords"": [], ""author"": """", ""license"": ""ISC"", ""dependencies"": { ""@vonage/server-sdk"": ""^3.14.0"", ""dotenv"": ""^16.4.5"", ""express"": ""^4.19.2"" } }
- Why
type: ""module""
? This tells Node.js to interpret.js
files using ES Module syntax instead of the older CommonJS (require
/module.exports
) syntax, aligning with modern JavaScript standards. - Dependency Versions: The versions listed are examples.
npm install
will fetch the latest compatible versions based on semantic versioning. For specific compatibility, you might pin versions, but generally, using the latest stable releases is recommended.
- Why
-
Create Core Files: Create the main application file and files for environment variables and Git ignore rules.
touch index.js .env .gitignore
index.js
: Our main application code..env
: Stores sensitive credentials like API keys (will not be committed to Git)..gitignore
: Specifies files and directories that Git should ignore.
-
Configure
.gitignore
: Addnode_modules
and.env
to your.gitignore
file to prevent committing dependencies and sensitive credentials.# .gitignore # Dependencies node_modules/ # Environment variables .env # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* # Optional Editor directories and files .idea .vscode *.suo *.ntvs* *.njsproj *.sln *.sw?
- Why ignore
node_modules
? This directory contains downloaded dependencies and can be very large. It should be regenerated usingnpm install
. - Why ignore
.env
? This file contains sensitive API keys and secrets and should never be committed to version control.
- Why ignore
2. Implementing Core Functionality (SMS Sending Logic)
We'll integrate the Vonage SDK to handle the actual SMS sending.
-
Import Dependencies: Open
index.js
and import the required modules.// index.js import express from 'express'; import { Vonage } from '@vonage/server-sdk'; import 'dotenv/config'; // Loads .env variables into process.env
- Why
dotenv/config
? Importing this module automatically loads the variables defined in your.env
file intoprocess.env
, making them accessible throughout your application. It's crucial to import it early.
- Why
-
Initialize Vonage SDK: Create an instance of the Vonage client using credentials loaded from environment variables.
// index.js (continued) // Input validation (basic): Ensure required env variables are set if (!process.env.VONAGE_API_KEY || !process.env.VONAGE_API_SECRET || !process.env.VONAGE_FROM_NUMBER) { console.error('Error: Missing required Vonage environment variables (VONAGE_API_KEY, VONAGE_API_SECRET, VONAGE_FROM_NUMBER).'); process.exit(1); // Exit if essential config is missing } const vonage = new Vonage({ apiKey: process.env.VONAGE_API_KEY, apiSecret: process.env.VONAGE_API_SECRET }); const fromNumber = process.env.VONAGE_FROM_NUMBER;
- Why initialize outside the route? Creating the Vonage client instance once when the application starts is more efficient than creating it for every incoming request. Node.js module scope handles this naturally.
-
Create the SMS Sending Function: While we could put the logic directly in the route, let's define an asynchronous function for clarity. We'll use the
vonage.sms.send()
method provided by the SDK, which corresponds to the simpler Vonage SMS API (distinct from the multi-channel Messages API).// index.js (continued) async function sendSms(to, text) { try { const resp = await vonage.sms.send({ to, from: fromNumber, text }); console.log('Message submitted to Vonage.'); console.dir(resp); // Log the full response for debugging // Check Vonage response status for the SMS API via the SDK. // A status of '0' indicates Vonage accepted the message submission. // Note: This does not guarantee final delivery to the handset. if (resp?.messages?.[0]?.['status'] === '0') { console.info(`Message accepted by Vonage. Message ID: ${resp.messages[0]['message-id']}`); return { success: true, messageId: resp.messages[0]['message-id'] }; } else { // Log the specific error text from Vonage if available const status = resp?.messages?.[0]?.['status'] ?? 'Unknown'; const errorText = resp?.messages?.[0]?.['error-text'] ?? 'No error text provided.'; console.error(`Message submission failed. Status: ${status}, Error: ${errorText}`); return { success: false, error: `Vonage API Error: ${errorText} (Status: ${status})` }; } } catch (err) { console.error('Error sending SMS via Vonage SDK:', err); // Handle potential network errors or SDK issues return { success: false, error: 'Failed to send SMS due to an unexpected error during API communication.' }; } }
- Why
async/await
? Thevonage.sms.send()
method is asynchronous (it involves network communication).async/await
provides a cleaner way to handle promises compared to.then().catch()
. - Why check
resp?.messages?.[0]?.['status'] === '0'
? For thevonage.sms.send
method (using the older SMS API), the response contains amessages
array. For a single message, checking thestatus
of the first element is standard. A status of'0'
signifies successful submission to Vonage. Other statuses indicate specific issues (e.g., invalid number, insufficient funds, throttling), and theerror-text
provides details. The optional chaining (?.
) adds safety in case the response structure is unexpected.
- Why
3. Building a Complete API Layer
Now, let's set up the Express server and define the API endpoint.
-
Initialize Express App: Create the Express application instance and configure middleware for parsing JSON request bodies.
// index.js (continued) const app = express(); const PORT = process.env.PORT || 3000; // Use port from .env or default to 3000 // Middleware to parse JSON bodies app.use(express.json()); // Middleware to parse URL-encoded bodies (optional but good practice) app.use(express.urlencoded({ extended: true }));
- Why
express.json()
? This middleware automatically parses incoming requests withContent-Type: application/json
and makes the parsed data available onreq.body
. - Why
express.urlencoded()
? Parses incoming requests withContent-Type: application/x-www-form-urlencoded
.extended: true
allows for rich objects and arrays to be encoded.
- Why
-
Define the
/send-sms
Endpoint: Create a POST route that accepts the recipient number (to
) and message (text
) in the request body.// index.js (continued) app.post('/send-sms', async (req, res) => { const { to, text } = req.body; // Basic Input Validation if (!to || !text) { return res.status(400).json({ success: false, error: 'Missing required fields: ""to"" and ""text"".' }); } // Basic 'to' number format validation (improve as needed) // Example: Check if it starts with '+' and contains only digits (E.164 basic check) if (!/^\+[1-9]\d{1,14}$/.test(to)) { return res.status(400).json({ success: false, error: 'Invalid ""to"" number format. Use E.164 format (e.g., +12125551234).' }); } console.log(`Received request to send SMS to ${to}: ""${text.substring(0, 50)}...""`); // Log snippet const result = await sendSms(to, text); if (result.success) { res.status(200).json({ success: true, messageId: result.messageId }); } else { // Return a server error status. The specific Vonage error is logged internally. // Consider whether to expose result.error directly to the client based on security needs. res.status(500).json({ success: false, error: result.error || 'Failed to send SMS.' }); } });
- Why
async
route handler? Because it calls theasync
functionsendSms
, the handler itself needs to beasync
to useawait
. - Why basic validation? Prevents unnecessary API calls with invalid data and provides immediate feedback to the client. More robust validation (e.g., using libraries like
joi
orexpress-validator
) is recommended for production. The regex checks for a basic E.164 format. - Why
res.status()
? Setting appropriate HTTP status codes (400 for bad request, 200 for success, 500 for server error) is crucial for REST API design.
- Why
-
Start the Server: Tell the Express app to listen for incoming connections on the specified port.
// index.js (continued) app.listen(PORT, () => { console.log(`Server listening on http://localhost:${PORT}`); console.log(`API Endpoint: POST http://localhost:${PORT}/send-sms`); });
4. Integrating with Vonage (Credentials and Configuration)
Proper configuration is key to connecting to the Vonage API.
-
Obtain Vonage Credentials:
- Navigate to your Vonage API Dashboard.
- On the main dashboard page (Getting Started), you will find your API key and API secret. Copy these values.
- Important: Treat your API secret like a password – keep it confidential.
-
Get a Vonage Number / Configure Test Numbers:
- Purchased Number: Navigate to Numbers -> Your numbers. If you have purchased a Vonage virtual number, copy it. This will be your
FROM
number. - Trial Account (Test Numbers): If you are using a free trial account, Vonage restricts sending SMS to only verified numbers initially.
- Go to Numbers -> Test numbers.
- Click Add test number.
- Enter the phone number you want to send test messages to (e.g., your personal mobile number).
- Verify the number using the code sent via SMS or voice call.
- Crucially: You must add every recipient number to this list while in trial mode.
- Sender ID: For the
FROM
number (VONAGE_FROM_NUMBER
in.env
), you can often use your purchased Vonage number. In some countries, you might use an Alphanumeric Sender ID (like ""MyCompany""), but support varies. For testing, using your purchased Vonage number is reliable. If using trial mode without a purchased number, you might need to check Vonage documentation or support for the appropriate sender ID (it might default to a shared short code or generic ID). For this guide, we assume you have a purchased number or have clarified the correct sender ID for trial mode.
- Purchased Number: Navigate to Numbers -> Your numbers. If you have purchased a Vonage virtual number, copy it. This will be your
-
Configure Environment Variables: Open the
.env
file you created earlier and add your credentials and Vonage number.# .env # Server Port PORT=3000 # Vonage API Credentials VONAGE_API_KEY=YOUR_VONAGE_API_KEY_HERE VONAGE_API_SECRET=YOUR_VONAGE_API_SECRET_HERE # Vonage Number (or approved Sender ID) to send SMS From # Use E.164 format (e.g., +14155550100) VONAGE_FROM_NUMBER=YOUR_VONAGE_VIRTUAL_NUMBER_HERE
- Replace the placeholder values with your actual Key, Secret, and Vonage Number.
PORT
: The port your Express server will run on locally.VONAGE_API_KEY
: Your public Vonage API key.VONAGE_API_SECRET
: Your confidential Vonage API secret.VONAGE_FROM_NUMBER
: The Vonage number (in E.164 format) or approved Alphanumeric Sender ID that the SMS will appear to come from.
5. Implementing Error Handling and Logging
We've already added basic error handling, but let's refine the logging.
-
Refined Logging: Our current
console.log
andconsole.error
are basic. For production, consider using a dedicated logging library likewinston
orpino
for structured logging (e.g., JSON format), log levels (info, warn, error), and log rotation.Example (Conceptual - using console for simplicity here):
// Inside sendSms function - error block } catch (err) { // Log with more context using structured logging principles console.error({ timestamp: new Date().toISOString(), level: 'error', message: 'Failed to send SMS via Vonage API SDK call', errorMessage: err.message, // Log only the message for brevity, or err for full stack // errorStack: err.stack, // Optionally log stack for detailed debugging // context: { to, text } // Optionally log context, be mindful of PII }); return { success: false, error: 'Failed to send SMS due to an unexpected error.' }; } // Inside /send-sms route - successful send if (result.success) { console.info({ // Use info level for successful operations timestamp: new Date().toISOString(), level: 'info', message: 'SMS sent successfully via API endpoint', to: to, // Be careful logging PII like phone numbers in production logs messageId: result.messageId }); res.status(200).json({ success: true, messageId: result.messageId }); }
-
Retry Mechanisms: Network issues or temporary Vonage service problems can cause failures. Implementing a retry strategy can improve reliability.
- Simple Retry: You could wrap the
vonage.sms.send
call in a loop with a short delay. - Exponential Backoff: A better approach is to increase the delay between retries (e.g., 1s, 2s, 4s). Libraries like
async-retry
can simplify this. - Caveat: Be cautious with retries for SMS sending. Retrying after Vonage has already accepted the message (but before confirming delivery) could lead to duplicate messages. Only retry on initial connection errors or specific non-final error codes from Vonage if their documentation advises it. For this basic guide, we won't implement automatic retries in the application layer, relying on the initial success/failure check.
- Simple Retry: You could wrap the
6. Creating a Database Schema and Data Layer
Not applicable for this simple guide. This application is stateless and doesn't require a database to store information about sent messages (though a production system might log message IDs and statuses to a database for tracking).
7. Adding Security Features
Security is paramount, especially when handling API keys and potentially user data.
-
API Key Security:
- Environment Variables: As implemented, using
.env
keeps keys out of the code. .gitignore
: Ensures.env
isn't committed.- Production Environment: Use your hosting provider's mechanism for managing secrets (e.g., AWS Secrets Manager, Heroku Config Vars, Vercel Environment Variables). Never hardcode keys in production code.
- Environment Variables: As implemented, using
-
Input Validation:
- We added basic checks for
to
andtext
presence andto
format. - Recommendation: Use a dedicated validation library (
joi
,express-validator
) for more complex rules (e.g., message length limits, character set validation).
Install Joi example:
npm install joi
Illustrative example using Joi for validation (add to
index.js
if implementing):import Joi from 'joi'; const sendSmsSchema = Joi.object({ to: Joi.string().pattern(/^\+[1-9]\d{1,14}$/).required().messages({ 'string.pattern.base': 'Invalid ""to"" number format. Use E.164 format (e.g., +12125551234).', 'any.required': '""to"" field is required.' }), text: Joi.string().min(1).max(1600).required().messages({ // Example length limits 'string.min': '""text"" cannot be empty.', 'string.max': '""text"" exceeds maximum length (1600 characters).', 'any.required': '""text"" field is required.' }) }); app.post('/send-sms', async (req, res) => { const { error, value } = sendSmsSchema.validate(req.body); if (error) { console.warn('Validation Error:', error.details[0].message); return res.status(400).json({ success: false, error: error.details[0].message }); } const { to, text } = value; // Use validated values // ... rest of the handler logic using 'to' and 'text' from 'value' console.log(`Received valid request (Joi) to send SMS to ${to}: ""${text.substring(0, 50)}...""`); const result = await sendSms(to, text); // ... handle result as before });
- We added basic checks for
-
Rate Limiting: Protect your API endpoint (and your Vonage account balance) from abuse by limiting the number of requests a client can make in a given time window.
- Recommendation: Use middleware like
express-rate-limit
.
Install express-rate-limit example:
npm install express-rate-limit
Illustrative example using basic rate limiting (add to
index.js
if implementing):import rateLimit from 'express-rate-limit'; const smsLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per windowMs standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers legacyHeaders: false, // Disable the `X-RateLimit-*` headers message: { success: false, error: 'Too many SMS requests from this IP, please try again after 15 minutes' } }); // Apply the rate limiting middleware to the specific SMS route app.post('/send-sms', smsLimiter, async (req, res) => { // Handler logic remains the same, rate limiter runs before it // ... });
- Recommendation: Use middleware like
-
Authentication/Authorization (Beyond Scope): This simple API is open. In a real application, you would protect this endpoint:
- API Key: Require clients to send a secret API key in headers.
- JWT/OAuth: Implement standard authentication flows if users are triggering the SMS.
8. Handling Special Cases
Real-world SMS sending involves nuances.
-
Number Formatting (E.164):
- Requirement: Vonage (and most SMS providers) require numbers in E.164 format:
+
followed by country code, then the number without spaces or symbols (e.g.,+14155550100
,+442071838750
). - Action: Ensure any user input is normalized to this format before sending to the API. Our basic validation checks this pattern. Libraries like
libphonenumber-js
can provide robust parsing and validation.
- Requirement: Vonage (and most SMS providers) require numbers in E.164 format:
-
Trial Account Whitelisting:
- Problem: Sending fails with ""Non-Whitelisted Destination"" if the recipient isn't added to the Test Numbers list in the Vonage dashboard during the trial period.
- Action: Ensure target numbers are added and verified in the Vonage dashboard under Numbers -> Test numbers. This is the most common issue for new users.
-
Character Limits and Encoding:
- Standard SMS messages have character limits (e.g., 160 GSM characters, fewer for UCS-2/Unicode). Longer messages are split into multiple segments (concatenated SMS), billed separately.
- Using non-GSM characters (like emojis or certain accented letters) forces UCS-2 encoding, reducing the per-segment limit significantly (~70 characters).
- Action: Be aware of potential costs for long messages or messages with Unicode characters. Validate text length if necessary (
text.length
). The Vonage SDK/API handles segmentation automatically. Consider adding length checks in validation (as shown in the Joi example).
-
Sender ID Restrictions:
- Using Alphanumeric Sender IDs (e.g., ""MyCompany"") is not supported in all countries (e.g., the US often requires pre-registration or use of short codes/virtual numbers).
- Action: Use your purchased Vonage virtual number as the
FROM
number for maximum compatibility, especially when starting. Check Vonage's country-specific guidelines if you need Alphanumeric Sender IDs.
9. Implementing Performance Optimizations
For this simple application, performance bottlenecks are unlikely to be in the Node.js code itself, but rather in the latency of the external Vonage API call.
- SDK Initialization: As done, initialize the Vonage SDK instance once outside the request handler.
- Asynchronous Handling: Node.js and Express handle concurrent requests efficiently due to the non-blocking I/O model. The
async
/await
pattern ensures the server isn't blocked while waiting for Vonage's response. - Load Testing (Beyond Scope): For high-throughput scenarios, tools like
k6
,artillery
, orautocannon
could be used to simulate load and identify potential bottlenecks (e.g., CPU limits, Vonage API rate limits).
10. Adding Monitoring, Observability, and Analytics
For production readiness, monitoring is essential.
-
Health Checks:
- Add a simple health check endpoint (e.g.,
GET /health
) that returns a 200 OK status if the server is running. This is useful for load balancers and uptime monitoring services.
// index.js (Add this route before app.listen) app.get('/health', (req, res) => { res.status(200).json({ status: 'UP', timestamp: new Date().toISOString() }); });
- Add a simple health check endpoint (e.g.,
-
Logging: As discussed in Section 5, implement structured logging to capture errors and key events. Send these logs to a centralized logging service (e.g., Datadog, Logz.io, AWS CloudWatch Logs).
-
Error Tracking: Integrate an error tracking service (e.g., Sentry, Bugsnag) to capture, aggregate, and alert on unhandled exceptions or significant errors.
-
Metrics: Track key metrics:
- Request rate to
/send-sms
. - Request latency for
/send-sms
. - Error rate (4xx and 5xx responses).
- Vonage API call success/failure rate.
- Node.js process metrics (CPU, memory).
- Tools like Prometheus/Grafana or managed APM (Application Performance Monitoring) solutions can track these.
- Request rate to
11. Troubleshooting and Caveats
Common issues and their solutions:
-
Error:
Non-Whitelisted Destination
(Vonage Response)- Cause: You are using a Vonage trial account, and the recipient phone number (
to
) has not been added and verified in your Vonage Dashboard under Numbers -> Test numbers. - Solution: Log in to the Vonage Dashboard, navigate to Numbers -> Test numbers, and add/verify the destination number.
- Cause: You are using a Vonage trial account, and the recipient phone number (
-
Error:
Authentication failed
orInvalid Credentials
(Vonage Response)- Cause: The
VONAGE_API_KEY
orVONAGE_API_SECRET
in your.env
file is incorrect or doesn't match the credentials in your Vonage Dashboard. - Solution: Double-check the API Key and Secret in your Vonage Dashboard (API Settings) and ensure they are correctly copied into your
.env
file. Make sure the.env
file is being loaded correctly (check for typos indotenv/config
import or ensure the server was restarted after changes).
- Cause: The
-
Error:
Invalid Sender Address (From)
(Vonage Response)- Cause: The
VONAGE_FROM_NUMBER
in your.env
file is not a valid Vonage number associated with your account or an approved Sender ID for the destination country. - Solution: Verify the number exists in Numbers -> Your numbers in the Vonage Dashboard. Ensure it's in E.164 format. If using an Alphanumeric ID, check Vonage's country regulations.
- Cause: The
-
Error:
Invalid 'to' number format. Use E.164 format...
(API Response)- Cause: The
to
number provided in the POST request body is not in the correct E.164 format (e.g., missing+
, contains spaces or dashes). - Solution: Ensure the client sending the request formats the number correctly (e.g.,
+12125551234
).
- Cause: The
-
Error:
Missing required fields: ""to"" and ""text""
(API Response)- Cause: The POST request body did not include the
to
ortext
fields, or they were empty. - Solution: Ensure the client sends a JSON body including both fields with non-empty values.
- Cause: The POST request body did not include the
-
No SMS Received, but API returns Success (200 OK):
- Cause: Delivery issues downstream (carrier filtering, incorrect number but valid format, device issues). The Vonage
message-id
is returned, indicating Vonage accepted the message. - Solution: Use the
message-id
to check delivery status via Vonage APIs or logs if available. Double-check the recipient number is correct and the device has service. Check for carrier filtering.
- Cause: Delivery issues downstream (carrier filtering, incorrect number but valid format, device issues). The Vonage
-
Dependency Version Conflicts:
- Cause: Incompatibility between Node.js version, Express, or Vonage SDK versions.
- Solution: Ensure you are using compatible versions. Check the documentation for each library. Use
npm ls
to view the dependency tree and identify potential issues. Consider usingnpm ci
for consistent installs based onpackage-lock.json
.
12. Deployment and CI/CD
Deploying a Node.js application:
-
Choose a Platform: Common choices include:
- PaaS (Platform-as-a-Service): Heroku, Vercel, Render (often easier for simple apps).
- IaaS (Infrastructure-as-a-Service): AWS (EC2, Lambda, Fargate), Google Cloud (Compute Engine, Cloud Run), Azure (App Service, Functions).
- Containers: Dockerizing the app and deploying to Kubernetes, ECS, etc.
-
Environment Variables: Configure
PORT
,VONAGE_API_KEY
,VONAGE_API_SECRET
, andVONAGE_FROM_NUMBER
securely using the platform's environment variable management. Do not commit your.env
file. -
Build Process: For simple apps like this, often no build step is needed. For more complex setups (e.g., TypeScript), you'd add a build script to
package.json
. -
Running the App: Ensure the platform runs your application using
npm start
ornode index.js
. Use a process manager likepm2
for better stability, logging, and clustering in non-serverless environments. -
CI/CD Pipeline (e.g., GitHub Actions):
- Create a workflow file (e.g.,
.github/workflows/deploy.yml
). - Trigger: On pushes to the
main
branch. - Steps:
- Check out code.
- Set up Node.js.
- Install dependencies (
npm ci
- usespackage-lock.json
for exact versions). - (Optional) Run linters/tests.
- Deploy to your chosen platform (using CLI tools like
heroku deploy
,vercel deploy
, AWS CLI, etc.). Store platform API keys/tokens as GitHub Secrets.
Example GitHub Actions workflow for Heroku (adapt for your platform):
# .github/workflows/deploy.yml name: Deploy to Heroku on: push: branches: [ main ] # Or your deployment branch jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Use latest checkout action - uses: actions/setup-node@v4 # Use latest setup-node action with: node-version: '18' # Specify your Node.js version cache: 'npm' - name: Install dependencies run: npm ci # Use ci for faster, consistent installs in CI # Add build/test steps here if needed # e.g., npm run build # e.g., npm test - name: Deploy to Heroku uses: akhileshns/heroku-deploy@v3.12.14 # Check for latest version of deploy action with: heroku_api_key: ${{ secrets.HEROKU_API_KEY }} # Store Heroku key in GitHub Secrets heroku_app_name: ""your-heroku-app-name"" # Replace with your Heroku app name heroku_email: ""your-heroku-email@example.com"" # Replace with your Heroku account email
- Create a workflow file (e.g.,