Picture this: You’re in a remote desert area where there’s been a historic archaeological settlement found. Through the initial investigations, it appears this band of people didn’t have the greatest luck surviving. This is why you’re there. You’re looking for clues to see if you can put together an accurate picture of why their luck ran out.

Through your searching and searching you’re not uncovering much that’s helpful when suddenly- bam! You uncover an object that seems to be the keystone to explaining what went on here. This artifact you’ve found was just what you needed to inform you and help you understand what happened.

Imagine having these types of key clues for your test runs, builds, and more! CircleCI has you covered, though since we can’t give the system artifacts like sandy pieces of pottery, swords, or silver monkeys, let’s take a look at what we can create and a few ways that we can use those items.

Let’s go over what artifacts are

What are artifacts exactly? Taken from the documentation, “Artifacts persist data after a job is completed and may be used for longer-term storage of the outputs from your build process.” If this still seems nebulous to you, let’s break it down.

Throughout your workflow, each job has its own data and files that are wiped after each run. To carry data across jobs, it can be persisted to the workspace, which is a temporary data store specific to each workflow. Just like with jobs, the workspace data is gone after the workflow finishes. What gives? How do we keep items after workflows that may be useful to us?

We store those items as artifacts. As shown in the diagram below, you’ve got an extra step to move files to storage that sticks around even after your workflows are done.

How do we use artifacts and where are they configured?

In order for artifacts to be useful, they need to be accessible. Simply covering them in dirt and hoping someone in a thousand years happens to find them is not very helpful. Luckily for us, storing artifact files is a very simple process that happens in your config.yml file via the aptly named built-in step: store_artifacts. Say you’ve got a directory of screenshots that you’ve taken when testing visual regression of your website and let’s say those are stored at /tmp/screenshots.

The simplest way to accomplish saving them as artifacts in your config would look like this:

- store_artifacts:
    path: /tmp/screenshots

Here’s what it looks like in a full config:

version: 2
jobs:        
    build_and_save: 
        docker:
        - image: circleci/golang:latest
        steps:
            - checkout
            - run: make build
            - store_artifacts:
                path: /bin/final_build
workflows:
    version: 2
    main:
        jobs:
            - build_and_save

That’s it! It’s really that simple. 🎉

If you’d like to specify a prefix that’s used when accessing the artifacts via the artifacts API, you can specify that by adding another line like this:

- store_artifacts:
    path: /tmp/screenshots
    destination: screenshot

More on downloading artifacts via the API can be found in the documentation.

What are some real world examples of artifacts?

We now know how we can save and access our artifacts, what would we even want to save? Here’s a brief list of some items that could be saved for long term use:

  • Screenshots of test steps or failures
  • Test results
  • APKs/Binaries
  • Performance output from a stress test
  • Log files
  • Core dumps
  • Coverage files

Based on what makes sense for your needs, you may save some of these items or none of them, and that’s perfectly okay. CircleCI doesn’t care and what’s important is what’s most useful and helpful for your needs. (If you save artifacts that aren’t listed above, leave a comment and let us know what!)

Saving files is great and all, but what’s the use if they’re not used? Good point!

  • If you’ve got screenshots you’re saving, after a failed run, you could pull up the screenshot in the Artifacts tab of a job and see exactly what’s different in a visual regression, or where your site was at when Selenium couldn’t find a button. If you’d like to take this one step further, you could even set up an integration with your favorite messaging platform and have a message sent on failure with the very same screenshot, saving you time!
  • If you’re creating apps you could save a version of your built Android code to then be distributed afterward.
  • If your log files output are quite large and you’d like to have them accessible by some software for parsing, you can do that, too.

In Conclusion

The sky is the limit with what you choose to use artifacts for. They’re a simple concept to learn and implement, but their power comes into play by enabling you and your team to further fine tune and supplement your CI/CD process in deeper ways than just pass/fail.

Thanks for reading!


Jayson Smith is a continuously learning software engineer with a passion for testing, communication, and trying to improve the software development lifecycle for the folks that he interacts with. Primarily a Gopher, he blogs about his personal experience and learning on his website, writes software for Brightcove, organizes the Phoenix chapter of the Ministry of Test Meetup, is a maintainer/member of the Cucumber community, speaks about software, and consults.