Hugo helpfully supports the deployment of processed files to an S3 bucket, and the 1Password op command line utility makes injecting AWS access keys super easy and secure. This is far superior to the aws s3 sync command I had been running until now! 🤷‍♂️️

Set up

  1. Install 1Password cli and enable desktop app integration.

  2. Create IAM credentials, with permissions to perform S3 actions and store them in 1Password.

This is left as an exercise to the reader. 😄️

  1. Copy the 1Password secret references to the AWS Access Key ID and AWS Secret Access Key items.

  2. Create an environment variable file with those two links.

1Password’s full documentation of the environment variable file is simple and the file is flexible for all kinds of use cases. But for this example, it will only contain two lines:

AWS_ACCESS_KEY_ID = "op://Vault/blahblahblahblahblahblah/access key id"
AWS_SECRET_ACCESS_KEY = "op://Vault/blahblahblahblahblahblah/secret access key"

Save this file as prod.env (or whatever suits your fancy).

  1. Update hugo.yaml to include deployment target.

At the bottom of hugo.yaml, include a deployment section:

        - name: production
          URL: "s3://s3-bucket-name/"
          cloudFrontDistributionID: "0A1B2C3D4E5F6G"

The cloudFrontDistributionID element is optional, but helpful. But if you DO include it, take note of the warning below during deployment.

If your site content is in a subfolder of the S3 bucket, the URL would look more like this:

URL: "s3://s3-bucket-name/?prefix=foldername/"

(Refer to the Hugo Docs for more info on S3 configuration details for Hugo deployment.)


  1. Build the static pages

Run from the root of the repo:

hugo --loglLevel info --destination public/

(I like to include the log level for visibility, but to each his own!)

  1. Validate

For the cautious among you: validate the actions to be taken, using the --dryRun flag:

op run --env-file prod.env -- hugo deploy --logLevel info --confirm --dryRun --target production
  1. Deploy

Or skip straight to the actual deployment if you’re fearless:

op run --env-file prod.env -- hugo deploy --logLevel info --target production


If you’ve included the CloudFront Distribution ID in the Hugo deployment target, the deployment will invalidate the distribution cache, by default. Add the flag --invalidateCDN=false to the deploy command above to avoid that, if required.

Additional References