smithy_beam

Hex package for the smithy-beam code generator.

Generates Elixir and Erlang code from Smithy models (client and server).

Mix and rebar3 helper that runs the Smithy CLI to generate Elixir and Erlang code from Smithy models.

The Java codegen plugins are resolved from Maven Central. This Hex package is the BEAM-native compile-time glue.

Generation runs at compile time in the consumer project. Compiling smithy_beam itself as a dependency does not generate code.

Prerequisites

  1. Smithy CLI on PATH
    • macOS: brew tap smithy-lang/tap && brew install smithy-cli
    • Verify: smithy --help
  2. A JVM that can load the published codegen JARs (Java 21+)
  3. Network access on first build so the CLI can download Maven dependencies

Elixir (Mix)

def project do
  [
    compilers: [:smithy_beam] ++ Mix.compilers(),
    elixirc_paths: ["lib", "lib/generated"],
    smithy_beam: [
      models: "model",
      output: "lib/generated",
      language: :elixir,
      kind: :client,
      edition: "2026"
    ],
    deps: [
      {:smithy_beam, "~> 0.1", runtime: false}
    ]
  ]
end

Explicit task:

mix smithy_beam.generate
mix smithy_beam.generate --force

Erlang (rebar3)

{project_plugins, [smithy_beam]}.

{provider_hooks, [
  {pre, [{compile, {smithy_beam, generate}}]}
]}.

{smithy_beam, [
  {models, "model"},
  {output, "src/generated"},
  {language, erlang},
  {kind, client},
  {edition, "2026"}
]}.

Explicit task:

rebar3 smithy_beam generate

Configuration reference

Key Required Default Notes
models yes (unless config_file) Model file or directory
output no lib/generated / src/generated Destination for generated sources
language yes :elixir or :erlang
kind yes :client, :server, or :types
edition yes (auto config) Plugin edition, e.g. "2026"
service no Shape id when the model has multiple services
name no Optional module/file name stem
codegen_version no 0.3.1 Maven codegen artifact version
maven_deps no [] Extra GAV strings appended after defaults
config_file no Escape hatch: use an existing smithy-build.json
plugin with config_file derived Plugin id when using config_file

Default Maven dependencies always include the matching codegen-elixir or codegen-erlang coordinate plus common Smithy AWS-related artifacts. Consumer maven_deps are appended.

Versioning

Hex package version (smithy_beam) and Maven codegen versions are independent. Override the generator with codegen_version when needed.

Generated sources and git

Whether lib/generated / src/generated is committed is a consumer choice.

Custom HTTP clients

Generated clients dispatch HTTP through a pluggable adapter. By default Elixir uses RuntimeHttpClient.Req and Erlang uses runtime_http_client_httpc (OTP httpc). Override the adapter by setting http_client on the client config map passed into generated operations.

The adapter must implement the runtime HTTP client behaviour: one callback, request/1, that takes a built client request and returns an HTTP response or an error.

Elixir

Implement @behaviour RuntimeHttpClient. The request is a %RuntimeHttpClient.Request{} (method, url, headers, body). Return {:ok, %RuntimeTypes.HttpResponse{}} or {:error, reason}.

defmodule MyHttpClient do
  @behaviour RuntimeHttpClient

  alias RuntimeHttpClient.Request
  alias RuntimeTypes.HttpResponse

  @impl RuntimeHttpClient
  def request(%Request{method: method, url: url, headers: headers, body: body}) do
    # call your HTTP stack with method, url, headers, and body
    {:ok, %HttpResponse{status: 200, headers: [], body: ""}}
  end
end

Pass the module in config:

config = %{
  base_url: "https://api.example",
  http_client: MyHttpClient
}

MyServiceClient.get_item(config, input)

Erlang

Implement -behaviour(runtime_http_client). Include runtime_http_client.hrl and runtime_types.hrl. The request is #http_client_request{} (method, url, headers, body). Return {ok, #http_response{}} or {error, Reason}.

-module(my_http_client).
-behaviour(runtime_http_client).

-include("runtime_types.hrl").
-include("runtime_http_client.hrl").

-export([request/1]).

request(#http_client_request{
    method = Method,
    url = Url,
    headers = Headers,
    body = Body
}) ->
    %% call your HTTP stack with Method, Url, Headers, and Body
    {ok, #http_response{status = 200, headers = [], body = <<>>}}.

Pass the module in config:

Config = #{
    base_url => <<"https://api.example">>,
    http_client => my_http_client
},
my_service_client:get_item(Config, Input).

Typical uses: swap in Finch, Gun, or another HTTP stack; inject mocks in tests; add tracing or custom TLS settings around the request.

Publishing this package

Maven codegen JARs and this Hex package ship on separate channels and version lines.

Hex CI (.github/workflows/hex-publish.yml) runs on pushes to v3 that touch hex/smithy_beam/**, and on manual workflow_dispatch (dry-run by default).

To release a new Hex version:

  1. Change packaged files under hex/smithy_beam/ as needed.
  2. Bump @version in mix.exs and vsn in src/smithy_beam.app.src to the same new value.
  3. Push to v3. If that version is not yet on hex.pm, the workflow publishes it. If the version already exists and packaged files changed, the job fails so you bump again.
  4. Confirm at https://hex.pm/packages/smithy_beam

Requires repository secret HEX_API_KEY. Manual fallback: cd hex/smithy_beam && mix hex.publish.

Maven releases stay on git tags v* via .github/workflows/release.yml and do not publish Hex.