Skip to content

Repository files navigation

awso - OCaml AWS client

Forked from awsm which is Copyright (c) Solvuu, Inc. Released under the MIT license.

Pure OCaml client for AWS. Code is auto-generated for all services based on the API declared in botocore. Higher level functions are sometimes provided on top of this base to (e.g.) support multi-part uploads to S3.

Features

Nearly all of AWS's 400+ APIs are supported (generated from botocore 1.43.9, freshened 2026-05-17). Three I/O flavors:

  • awso-eio - Effects based Eio backend
  • awso-lwt — Lwt backend
  • awso-async — Jane Street Async backend
  • awso-sync — synchronous (blocking) backend; uses libcurl under the hood

There is additionally a command-line tool awso-cli for all APIs composed using Core.Command.

Getting started

opam install awso-eio     # Eio
opam install awso-lwt     # Lwt
opam install awso-async   # Async
opam install awso-sync    # synchronous (blocking)
opam install awso-cli     # umbrella CLI binary

Note: the AWS surface is massive and this package can take a lengthy amount of time and space to build.

Examples

See the examples directory.

Here is a short example that lists all EC2 instances using Eio:

(* ec2_describe_instances.ml *)
module Ec2 = Awso_ec2_eio

let print_row a b c d = Printf.printf "%-16s  %-15s  %-39s  %-20s\n" a b c d

let print_instance instance =
  let name =
    Option.bind instance.Ec2.Instance.tags (fun tags ->
      List.find_map
        (function
          | { Ec2.Tag.key = Some "Name"; value = Some v } -> Some v
          | _ -> None)
        tags)
  in
  let instance_type =
    match instance.instanceType with
    | Some it -> Ec2.InstanceType.to_string it
    | None -> ""
  in
  print_row
    instance_type
    (Option.value instance.publicIpAddress ~default:"")
    (Option.value instance.ipv6Address ~default:"")
    (Option.value name ~default:"")
;;

let main env =
  let cfg = Awso_eio.Cfg.get_exn ~env () in
  match Ec2.describe_instances ~cfg (Ec2.DescribeInstancesRequest.make ()) with
  | Error e ->
    failwith
      (Printf.sprintf
         "Ec2.describe_instances: %s"
         (Yojson.Safe.to_string (Ec2.Ec2_error.to_json e)))
  | Ok { reservations; _ } -> (
    let instances =
      reservations
      |> Option.value ~default:[]
      |> List.concat_map (function
        | { Ec2.Reservation.instances = None; _ } -> []
        | { instances = Some instances; _ } -> instances)
    in
    match instances with
    | [] -> print_endline "no instances"
    | instances ->
      print_row "instance-type" "public ipv4" "public ipv6" "name";
      print_row
        (String.make 16 '-')
        (String.make 15 '-')
        (String.make 39 '-')
        (String.make 20 '-');
      List.iter print_instance instances)
;;

let () = Eio_main.run main ;;
; dune
(executable
 (name ec2_describe_instances)
 (libraries awso-eio.ec2 eio_main))

Make sure to populate ~/.aws/config and ~/.aws/credentials in the usual way, then:

dune exec ./ec2_describe_instances.exe

Repository layout

Path Purpose Shipped to opam?
lib/runtime/awso/ Core runtime: auth, HTTP, config, regions Yes (awso)
lib/runtime/eio/ Eio backend Yes (awso-eio)
lib/runtime/async/ Async backend Yes (awso-async)
lib/runtime/lwt/ Lwt backend Yes (awso-lwt)
lib/runtime/sync/ Synchronous (blocking) backend, libcurl-based Yes (awso-sync)
lib/common/ Jane Street Core compatibility shim Yes (awso-common)
aws/<service>/ Auto-generated per-service bindings (~400 services) Yes (under awso, awso-async, awso-lwt, awso-sync)
awso-cli/ A bit like the Python aws cli Yes (awso-cli)
lib/codegen/ The code generator that produces aws/<service>/ from botocore JSON No: private library
vendor/botocore/ Vendored botocore JSON used by the codegen No
dogfood/ Important maintainer tools that use awso itself No
examples/ Example programs No, not installed

Why is the aws/ tree committed to git?

aws/<service>/ contains roughly 400 services worth of generated OCaml. We commit it on purpose so that opam install awso-async (or any sibling package) never has to run the codegen at install time. End users get a ~25 dependency build instead of ~50+: ppxlib, sedlex, ocamlgraph, and the rest of the codegen toolchain stay private to maintainers. The decision trades repo size for install-time simplicity and predictability.

Regeneration is a maintainer concern, but you can re-generate yourself like so:

make generate-code

After regenerating, commit the resulting diff alongside whatever change prompted it.

Documentation

Generate API docs locally with opam install odoc then make doc.

About

OCaml bindings for all of AWS

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages