{"id":51311947,"url":"https://github.com/giwiro/image-compress-lambda","last_synced_at":"2026-07-01T04:32:48.052Z","repository":{"id":41385254,"uuid":"502352521","full_name":"giwiro/image-compress-lambda","owner":"giwiro","description":"Node.js AWS lambda handler for compressing and resizing images on the fly.","archived":false,"fork":false,"pushed_at":"2022-07-01T22:25:20.000Z","size":539,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-04-14T23:44:59.233Z","etag":null,"topics":["aws","aws-cloudformation","aws-lambda","image-processing","node-sharp","nodejs","swc"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/giwiro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-11T13:13:09.000Z","updated_at":"2022-06-13T03:50:16.000Z","dependencies_parsed_at":"2022-09-12T04:10:55.263Z","dependency_job_id":null,"html_url":"https://github.com/giwiro/image-compress-lambda","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/giwiro/image-compress-lambda","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giwiro%2Fimage-compress-lambda","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giwiro%2Fimage-compress-lambda/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giwiro%2Fimage-compress-lambda/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giwiro%2Fimage-compress-lambda/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/giwiro","download_url":"https://codeload.github.com/giwiro/image-compress-lambda/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giwiro%2Fimage-compress-lambda/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34993435,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-cloudformation","aws-lambda","image-processing","node-sharp","nodejs","swc"],"created_at":"2026-07-01T04:32:47.663Z","updated_at":"2026-07-01T04:32:48.004Z","avatar_url":"https://github.com/giwiro.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# image-compress-lambda\nNode.js AWS lambda handler for compressing and resizing images on the fly.\n\nThe aim of this project is to provide a lambda function which shrinks and compresses images on the fly, using S3 as\ndata repository.\n\n[![nodejs](https://badges.aleen42.com/src/node.svg)](https://nodejs.org/)\n[![types](https://badges.aleen42.com/src/typescript.svg)](https://www.typescriptlang.org/)\n[![lint](https://badges.aleen42.com/src/eslint.svg)](https://eslint.org/)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n[![License: GNU](https://img.shields.io/badge/License-GNU-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html)\n\n## Deployment\n\n1. Clone the repository.\n\n```\n$ git clone https://github.com/giwiro/image-compress-lambda.git\n```\n\n2. Install all dependencies.\n\n```\n$ npm install\n```\n\n3. Build the lambda code intro a zip file. This will generate a `build-zip` folder with a zip file in it.\n\n```\n$ npm run build\n```\n\n4. Upload the generated zip file along the cloudformation config file into an S3 bucket through a script in\n   `scripts/sync.ts`. This bucket will host just these 2 files: the `provision/main.yaml` and the\n   `lambda/image-compress-lambda.zip`, do not get confused with the bucket hosting the images. Also do not\n   forget to pass the environment variables: `S3_BUCKET` and `S3_REGION`.\n\n```\n$ S3_BUCKET=image-compress-lambda S3_REGION=us-east-1 npm run sync\n```\n   This will create a folder structure like this in your bucket.\n\n    /image-compress-lambda\n      ├── /lambda\n      │     └── image-compress-lambda.zip       # Lambda code zipped.\n      └── /provision\n            └── main.yaml                       # Cloudformation template for all resource creation.\n5. Deploy the uploaded `provision/main.yaml` into cloudformation and provide all required info. This will\n   create the `image-compress-lambda` function and optionally (recommended) the `disable-cache-cloudfront-lambda`\n   function.\n\n![parameters](resources/cf-parameters.png?raw=true)\n\n6. Configure the redirect rule for the S3 bucket hosting the images. (Check the **NOTE #2**)\n\n7. Configure the `disable-cache-cloudfront-lambda` as Lambda@Edge for the cloudfront distribution.\n\n## Stack\n\nFor the code itself we use `typescript` with `eslint` and `prettier` for code formatting. Additionally, we use\n`swc` (a very fast web compiler) along with some custom `javascript` build and configure scripts.\n\nIn order to control the deployment we used `cloudformation` configure files and a `bash` script for synchronize\nit with the S3 bucket.\n\n## Architecture\n\n![architecture](resources/image-compress-lambda-architecture.png?raw=true)\n\n1. The HTTP request first lands on Cloudfront which will perform ssl termination and cache for the s3 objects.\n   The format will be something like this: `\u003cpath\u003e/\u003cdimensions\u003e/\u003cfilename\u003e`.\n   For example: `/public/path/200x200/picture_1618444089.jpg`.\n   **(NOTE #1)**\n\n3. Cloudfront later will perform a reverse proxy to the S3 object website url.\n\n4. If the object is present in the bucket (404), then it is returned. Otherwise, it will redirect to the API Gateway.\n   **(NOTE #2)** **(NOTE #3)**\n\n5. The API Gateway will perform a call (invoke) to the aws lambda function.\n\n6. If the original object exists (without the `\u003cdimensions\u003e` part), then it will shrink and lower the quality of the image\n   to the required size. After that, the image get compressed with gzip algorithm through the zlib node.js library. Finally,\n   the generated thumbnail is uploaded to the S3 bucket.\n\n7. The lambda function returns a redirect (301) to the s3 thumbnail.\n\n8. Finally, the API Gateway returns the redirect response to the Cloudfront endpoint, and the client request will be\n   automatically redirected to the created resource.\n\n## Notes\n\n### NOTE 1\n\nPay attention to the request url to the s3 bucket hosting the images. It has a particular prefix `public`, but it does not have\nto be this exact keyword. It can be any prefix you like, but you will need it later for the S3 bucket redirect rule. \n\n### NOTE 2\n\nDo not forget to configure the S3 redirect rules when the object is absent (404). This rule will depend on the ApiGatewayStage\nand the prefix of the request url to the s3 bucket hosting the images.\n\n```json\n[\n  {\n    \"Condition\": {\n      \"HttpErrorCodeReturnedEquals\": \"404\",\n      \"KeyPrefixEquals\": \"\u003cprefix\u003e\"\n    },\n    \"Redirect\": {\n      \"HostName\": \"\u003capi_gateway_id\u003e.execute-api.\u003cregion\u003e.amazonaws.com\",\n      \"HttpRedirectCode\": \"307\",\n      \"Protocol\": \"https\",\n      \"ReplaceKeyPrefixWith\": \"\u003cstage\u003e/\u003cprefix\u003e\"\n    }\n  }\n]\n```\n\nIf the stage is \"local\" and the prefix is \"public\", then the rule would look like something like this:\n\n```json\n[\n  {\n    \"Condition\": {\n      \"HttpErrorCodeReturnedEquals\": \"404\",\n      \"KeyPrefixEquals\": \"public\"\n    },\n    \"Redirect\": {\n      \"HostName\": \"\u003capi_gateway_id\u003e.execute-api.\u003cregion\u003e.amazonaws.com\",\n      \"HttpRedirectCode\": \"307\",\n      \"Protocol\": \"https\",\n      \"ReplaceKeyPrefixWith\": \"local/public\"\n    }\n  }\n]\n```\n\n### NOTE 3\n\nThere might be a small (big) inconvenient that will cause an infinite loop.\n\nIn the step 3, after the object was not found and a redirection was returned to the client, cloudfront will cache this\nredirection (keep this in mind).\nThen, the thumbnail gets generated in the step 5 and then in step 6 it returns to the client a redirect pointing to the new\ngenerated thumbnail. At this point when the client is going to follow this redirect, it will hit cloudfront and instead of\nreturning the new s3 object, it will return what cached in the previous step (3).\n\nAt the end you will have the following loop: `3 -\u003e 4 -\u003e 5 -\u003e 3 -\u003e 4 -\u003e 5 -\u003e 3 -\u003e 4 -\u003e 5 ...`.\n\nOptionally this repo provides an inline function called `disable-cache-cloudfront-lambda` by default (it does not require to be\nhosted in S3). But if you want to provide it yourself, here are some pointers:\n\nThe solution will be something like this: Find a way so that cloudfront does not cache the temp redirects (302 or 307).\nSadly there is not a \"simple\" solution, because cloudfront is not that \"smart\".\n\nThe solution is to make cloudfront smart using `Lambda@Edge`. Basically, the idea is to create a lambda function that will\nlook something like this (node@12 the 14 is not supported by lambda@edge yet):\n\n```javascript\n'use strict';\n\nexports.handler = (event, context, callback) =\u003e {\n  const response = event.Records[0].cf.response;\n  \n  if (response.status.match(/^30[27]/)) {\n    response.headers['cache-control'] = [{ \n      key: 'Cache-Control', \n      value: 'no-cache, no-store, private' \n    }];\n  }\n  return callback(null, response);\n};\n\n```\n\nAn access role is also required. In cloudformation the property is `AssumeRolePolicyDocument` from the `AWS::IAM::Role`.\nIf you are configuring it manually, it is located in the tab `Trust relationships` in the role configuration in `IAM`.\nThe role looks like this (don't forget `edgelambda.amazonaws.com`):\n\n```json\n{\n  \"Version\": \"2012-10-17\",\n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Principal\": {\n        \"Service\": [\n          \"lambda.amazonaws.com\",\n          \"edgelambda.amazonaws.com\"\n        ]\n      },\n      \"Action\": \"sts:AssumeRole\"\n    }\n  ]\n}\n```\n\nFinally, you just need to link the cloudfront distribution with the lambda function we just created, I suggest you do it \nfrom the lambda panel (it can also be done from the cloudfront panel).\nIn the lambda panel, click on `Actions` and `Deploy Lambda@Edge`, after that select the correct cf distribution and event \ntype `origin-response`.\n\nPD: Do not forget to create a cloudfront invalidation in order to see the changes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiwiro%2Fimage-compress-lambda","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgiwiro%2Fimage-compress-lambda","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiwiro%2Fimage-compress-lambda/lists"}