AWS: Deploy a Real-World AWS Lambda

Xavier ReedXavier Reed
6 min read

Create, deploy and monitor a simple AWS lambda function in a real-world workflow, including securely using API keys/credentials, creating separate deployment environments, and more. Note this assumes you’ve already created an account on AWS (if not, you can follow https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html). We’ll do all steps in the AWS Management Console.


Step 1: Create the Lambda Function

  1. Navigate to Lambda: In the AWS Management Console, search for “Lambda” and click on it.

  2. Create Function: Click the orange “Create function” button.

  3. Choose “Author from scratch”.

  4. Configure basic settings:

  • Function name: Name it relevant to your project, eg your-lambda-name (for my case, it was “toast-sales-weekly-report”).

  • Runtime: Select “Node.js 22.x” (the latest available, or whichever runtime you need given your language preference).

  • Architecture: Can leave as x86_64

  • Click “Create function”.

Step 2: Add Your Lambda Code

Scroll down the following Function overview page and in the Code Source Editor (CSE) you’ll see some boilerplate code (you can click the right-facing arrow button in the help panel on the upper right corner to give yourself more space).

Let's quickly run it to get a general idea of how everything works.

  • Make the following updates to the handler() function in the supplied index.mjs file to quickly demo how to make and save your changes:
export const handler = async (event) => {
    console.log('testing 123');

  return {
    statusCode: 200,
    body: JSON.stringify('Your first lambda')
  };
}
  • On the left hand side of the CSE, press “Deploy” — this saves the changes you made. Now click “Test” button.

  • Name it anything you want for now, eg “test_output”. Press Save.

  • Keep everything as default, and press “Invoke” to run the code.

  • You should see the execution results at bottom in a terminal. From here on out you can just press the same blue “Deploy” and “Test” buttons to save then execute the lambda function, and you’ll always see your console logs output in between the START RequestId and END RequestId, like so:

START RequestId: ...                    ← Function execution begins
[Your console.log outputs go here]      ← All your logs appear in this section
END RequestId: ...                      ← Function execution ends
REPORT RequestId: ...                   ← Performance metrics

Note: Sometimes the test button can fail to run your lambda. If this happens, simply deploy to save first, and then reload the page.

Step 3: Create Deployment Environments

Once you’ve written the code, you’ll want to create separate environments to isolate development, staging, and production environments from each other. This way, you can develop safely in your dev environment without affecting your live prod code. You do this by creating aliases of your lambda for each environment (eg DEV, STAGING, and PROD), and then creating versions of your code (version 1, version 2, etc) for your aliases to point to.

  • While in the same function overview page in your lambda (as in step 2), go to Aliases tab → Create alias.

  • On the following Create alias page, create a separate alias for each desired deployment environment, and point to $LATEST version for now ($LATEST is always your "work in progress”, but we’ll update what version the aliases point to in later steps). Press Save. Repeat for each environment you want. For example:

  • Back on the function overview page in your desired lambda, go to “Actions” dropdown in upper right corner → Publish new version.

  • Give it any name you’d like, eg “test-version” (or version 1, version 2, etc). This creates an immutable version of the current code in your CSE.

  • Now, update your aliases to point to their appropriate versions. For example you may keep your DEV alias pointing to $LATEST so that latest changes after pressing “Deploy” are automatically reflected, but have STAGING alias point to version 1, PROD alias to version 2, etc. This is up to you. Each time you are ready to update an alias with any new code changes or features, simply publish a new version, and update that alias to that new immutable version, as we’ve done here.

And your CloudWatch Events/EventBridge trigger, or any other workflow you have or will set up in the future, should invoke your-lambda-name:PROD (not just the function name). This gives you complete control over what code runs in each environment while maintaining a single lambda function.

Step 4: Configure Environment Variables (for API keys)

Say you’re connecting to an API like so:


export const handler = async (event) => {
    try {
        // Your API call may look something like the following...
        const yourAccessToken = 'skjf559_6$0....';

        const response = await fetch('https://your-api-url.com', {
            method: "GET",
            headers: {
                'Authorization': `Bearer ${yourAccessToken}`,
                // etc...
              }
        });

        if (!response.ok){
            console.error(response.status, response.statusText)
        }

        // And process the data in some way...
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error('Error:', error);
    }
};

You’ll want connect to the API securely, so as not to hardcode your sensitive API keys and credentials (yourAccessToken), leaking them in the process. This will also encrypt the data as well. You can do so in the following way:

  • Go to Configuration tab → Environment variables

  • Click “Edit” → add environment variables

  • Add your API credentials  no quotes needed. Eg key = ACCESS_TOKEN, value = skjf559_6$0...

  • Click “Save”

  • You can now access them in your lambda as you typically would, eg process.env.YOUR_ENV_VAR if Node.js (or per your language/environment). Therefor:

export const handler = async (event) => {
    try {
        //...

        const response = await fetch('https://your-api-url.com', {
            method: "GET",
            headers: {
                'Authorization': `Bearer ${process.env.ACCESS_TOKEN}`,
                // etc...
              }
        });

        //...
    } catch(error) {
      //...
    }
};

Step 5: Adjust Function Settings

In same function overview page in your lambda, go to Configuration tab → General configuration → Edit:

  • Timeout: Change from 3 seconds to something like 3–5 minutes (depending on how long your script takes) — the timeout increase will give you enough time to complete the API calls. Setting a realistic timeout helps prevent incurring costs for unnecessary execution time from runaway tasks or functions stuck in a loop (Use CloudWatch and X-Ray to monitor function durations and adjust timeouts as needed to avoid unnecessary timeouts or excessive execution time.). Bear in mind Lambda has a 15-minute max timeout.

  • Memory: 512 MB should be sufficient for API calls. In general, to find the right memory configuration, monitor your functions with Amazon CloudWatch and set alarms if memory consumption is approaching the configured maximum.

Click “Save” when done.

Step 6: Monitor and Debug

  • CloudWatch Logs: Your console.log statements will appear here. Go to Cloudwatch (search for it) → logs → log groups → click on the desired lambda function → and click on the desired log stream (eg perhaps the latest one executed, so top most). On following page, you will see the output and results, and you can expand every line using the arrow on top left corner of the table:

  • Check execution: Go to Function overview page again (ie Lambda → Functions → Your function) → Monitor tab.

  • View logs: Click “View CloudWatch logs”


Summary

And thats it! This tutorial gave you a real-life scenario of what you would typically do in most professional projects working in AWS, that is — create an AWS lambda function, set up environment variables to securely connect to external APIs (and adjust lambda settings via timeout and memory settings in order to accommodate realistic external API network requests), create deployment environments via aliases in order to isolate coding environments, and monitor/debug your lambda functions.

In a next post, part 2, we’ll continue on common real-world software tasks in AWS, going more in depth into monitoring performance and health of your lambda functions, as well as automating lambda calls on a scheduled daily/weekly basis, and more.

Until then, happy coding!

0
Subscribe to my newsletter

Read articles from Xavier Reed directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Xavier Reed
Xavier Reed