aws

boto3とは|clientとresourceの違い・認証・リトライを実装で解説【2026年最新】

boto3とは|clientとresourceの違い・認証・リトライを実装で解説【2026年最新】

boto3はPythonからAWSのAPIを呼ぶためのSDKで、2026年9月時点の公式ドキュメントが示す版は1.43.97です。同じS3のファイル一覧を取るだけでも、boto3.clientboto3.resourceでは、コードの書き方も将来の拡張性も別物です。この記事では、どちらを選ぶかの根拠、認証情報が探される12段の順序、ページネーターでの全件取得、既定がlegacyになっているリトライ設定、ClientErrorでの分岐までを、公式ドキュメントの実値と動くコードで整理します。AWS Lambdaに同梱されている版をそのまま使ってよいかという実務の疑問にも答えます。

まとめ:boto3の版・API種別・認証で先に決めておく設計の要点

結論から書きます。新規に書くコードはclient側だけで組んでください。AWSのPython SDKチームは、resourceインターフェースへ新機能を追加する予定がないと公式ドキュメントに明記しており、新しいサービス機能へはclientからしか到達できません。

版の固定も先に決める話です。boto3はbotocoreと同じ版系列でしか動かない設計になっており、setup.pyの依存指定はbotocore>=1.43.97,<1.44.0という狭い範囲です。Lambdaで動かす場合、ランタイムに含まれるSDKの版はランタイムとリージョンで変わります。新しいAPIを叩くなら、同梱版を当てにせず自分のパッケージかレイヤーでピン留めしてください。

認証は12段の探索順序を把握していれば迷いません。環境変数は共有認証ファイルより先に評価されるため、CI上でAWS_ACCESS_KEY_IDが残っていると~/.aws/credentialsのプロファイルは読まれません。最後に、リトライの既定モードはlegacyです。standardやadaptiveを使いたい場合は明示設定が要ります。

boto3の役割とbotocore・AWS CLIが同じ版で噛み合う依存の実際

boto3は単体のライブラリではなく、下位のbotocoreにAPIの実処理を任せた薄い層です。AWS CLIも同じbotocoreを土台にしています。この構造を知っていると、「pipで入れたboto3が古いAPIパラメータを知らない」という症状の原因を、boto3ではなくbotocoreの版に絞り込めます。

boto3 1.43.97とbotocore 1.43.97系の固定版による依存指定

boto3のリポジトリにあるsetup.pyを見ると、依存はbotocore>=1.43.97,<1.44.0と書かれています。マイナー版の上限が閉じているため、botocoreだけを上げても引き上がりません。逆に、新しいサービスAPIを使いたいときはboto3を上げればbotocoreも付いてきます。

本番の依存指定は次のように固定します。開発機とCIとLambdaで別の版が入ると、パラメータ名の有無で挙動が分かれます。

# requirements.txt(版を固定する)
boto3==1.43.97

# 実際に読み込まれた版を確認する
python -c "import boto3, botocore; print(boto3.__version__, botocore.__version__)"

公式ドキュメントのトップはdocs.aws.amazon.com/boto3/latest/に移っています。boto3.amazonaws.com/v1/documentation/...の旧URLは301で転送されるため、社内wikiのリンクが古いままなら書き換えの対象です。

Python 3.9終了後に残る対応版3.10〜3.14とフリースレッドの扱い

boto3のREADMEには、2026年4月29日にPython 3.9のサポートが終了したと告知されています。Python Software Foundation側のEOL(2025年10月31日)に追随した措置です。setup.pyのpython_requires>= 3.10で、分類子には3.10から3.14までが並びます。

目を引くのはProgramming Language :: Python :: Free Threading :: 2 - Betaという分類子です。GILを外したビルドでの動作をベータとして表明しています。ただしLambdaの管理ランタイムではフリースレッドが無効化されているため、この恩恵を受けられるのは、コンテナイメージか自前ビルドを使う環境に限られます。

clientとresourceの違いと新機能が入らない側を避ける選択基準

入門記事の多くは「resourceのほうがPythonらしく書ける」と紹介します。書き味だけを見ればそのとおりです。ただし2026年時点で新規コードにresourceを選ぶ理由は、ほぼ残っていません。

公式が明記したresourceインターフェースへの新機能追加の停止

判断の根拠は公式ドキュメントの1文です。Resourcesのガイドには「The AWS Python SDK team does not intend to add new features to the resources interface in boto3」と書かれ、続けて新しいサービス機能へはclientインターフェースから到達するよう案内されています。

既存のインターフェースはboto3のライフサイクル中は動き続けるとも明記されているため、稼働中のコードを慌てて書き換える必要はありません。線引きはこうです。新規実装はclient。既存のresourceコードは、そのサービスで新機能を使う場面が来たときにその箇所だけclientへ寄せる。全面書き換えは費用に見合いません。

S3のオブジェクト一覧で比べるclientとresourceの記述量と戻り値

同じ処理を両方で書くと、記述の違いに加えて戻り値の差も明確です。resourceは反復子がオブジェクトを返し、clientは辞書を返します。辞書側はキーが存在しない場合があるため、response.get('Contents', [])のように受けます。

import boto3

# resource:オブジェクトとして返る(新機能は入らない側)
s3r = boto3.resource("s3")
for obj in s3r.Bucket("example-bucket").objects.filter(Prefix="logs/"):
    print(obj.key, obj.size)

# client:辞書で返る。キー欠落に備えて get で受ける
s3c = boto3.client("s3")
resp = s3c.list_objects_v2(Bucket="example-bucket", Prefix="logs/")
for obj in resp.get("Contents", []):
    print(obj["Key"], obj["Size"])

なおclientのメソッド名はAWS APIと1対1で対応し、スネークケースへ変換されます。パラメータはキーワード引数でしか渡せません。位置引数で書くと動かないため、list_objects_v2("example-bucket")のような書き方は通りません。

スレッド共有の可否で分かれるclient再利用とresource再生成の設計

並列処理を設計する際、スレッド間で共有できるかという観点では両者の性質は逆です。clientのガイドはclientを一般にスレッドセーフと説明し、スレッドプールへ1つのclientを渡す実装例を載せています。一方resourceのガイドはresourceインスタンスをスレッドセーフでないと明記し、スレッドやプロセスごとに生成し直すよう求めています。

プロセス間はどちらも共有できません。multiprocessingでワーカーを分けるなら、各プロセスの中でboto3.session.Session()から作り直す設計にしてください。ここを親プロセスの使い回しで書くと、負荷をかけたときだけ再現する接続エラーになります。

認証情報の解決順序12段とLambda・EC2・ローカルで効く経路

「ローカルでは動くのにCIで別アカウントへ繋がる」という事故は、ほぼ探索順序の理解不足から起きます。boto3は決まった順番で認証情報を探し、最初に見つかった時点で探索を止めます。

認証情報の環境変数が共有認証ファイルに優先する12段の探索順序

認証情報のガイドが示す順序は12段です。先頭から、client呼び出し時の引数、Session生成時の引数、環境変数、AssumeRoleプロバイダ、Web IDでのAssumeRole、IAM Identity Center、共有認証ファイル、コンソール認証情報でのログイン、AWS configファイル、Boto2設定ファイル、コンテナ認証情報プロバイダ、EC2のインスタンスメタデータ、と続きます。

実務で効くのは3番目と7番目の位置関係です。環境変数は共有認証ファイルより先にあるので、シェルにAWS_PROFILEではなくAWS_ACCESS_KEY_IDが残っていると、プロファイル指定は無視されます。切り分けはaws sts get-caller-identityより先に、boto3.Session().get_credentials().methodでどの経路が当たったかを見るのが速いやり方です。

Lambda・ECSのコンテナ認証とEC2のIMDSが置かれる位置

コンテナ認証情報プロバイダとIMDSは、12段の末尾に置かれています。つまりLambdaやECSでは、明示的な認証情報が何も無い状態で初めて実行ロールが使われます。環境変数にアクセスキーを入れてしまうと、せっかくのロールが素通りされる形です。

ローカルで複数アカウントを行き来するなら、プロファイルをSessionで分けます。プロファイルそのものの切り替えを楽にする道具としては、AWSumeによるIAMロール切替の仕組みも併せて検討できます。

import boto3

# 既定のプロファイルに引きずられないよう Session を分ける
staging = boto3.session.Session(profile_name="staging", region_name="ap-northeast-1")
prod = boto3.session.Session(profile_name="prod", region_name="ap-northeast-1")

print(staging.client("sts").get_caller_identity()["Account"])
print(prod.client("sts").get_caller_identity()["Account"])

# どの経路で認証情報が解決されたかを確認する
creds = staging.get_credentials()
print(creds.method)  # 例: shared-credentials-file / iam-role / env

ページネーターとwaiterで取りこぼしと待ち時間を制御する実装

S3のlist_objects_v2は1回で最大1000件しか返しません。件数の少ない検証環境では気づかず、本番で先頭1000件だけを処理するコードが出来上がります。boto3はこの継続取得を代行するページネーターを持っています。

get_paginatorとPaginationConfigの総件数・1ページ件数の制限

ページネーターのガイドによれば、PaginationConfigで指定できるのはMaxItems(返す総アイテム数の上限)、PageSize(1ページあたりの件数)、StartingToken(再開位置)の3つです。PageSizeはサービス側が前後する場合があると注記されている点に注意してください。

import boto3

client = boto3.client("s3", region_name="ap-northeast-1")
paginator = client.get_paginator("list_objects_v2")

pages = paginator.paginate(
    Bucket="example-bucket",
    Prefix="logs/2026/",
    PaginationConfig={"MaxItems": 5000, "PageSize": 500},
)

total = 0
for page in pages:
    total += len(page.get("Contents", []))
print(total)

絞り込みはできるだけサーバー側で行います。Prefixのような操作パラメータを渡せば、転送されるレスポンス自体が小さくなり、API呼び出し回数も減ります。

JMESPathのsearchとwaiterで条件抽出と状態待ちを短く書く方法

ページをまたいだ条件抽出にはPageIteratorsearch()を使います。JMESPath式が各ページに適用され、条件に該当する要素が1件ずつ流れてくる仕組みです。状態遷移の待ち合わせにはget_waiterがあり、利用できる名前はwaiter_namesで確認できます。

import boto3

client = boto3.client("s3", region_name="ap-northeast-1")

# 100バイト超のオブジェクトだけをページ横断で拾う
pages = client.get_paginator("list_objects_v2").paginate(Bucket="example-bucket")
for key in pages.search("Contents[?Size > `100`][]"):
    print(key["Key"], key["Size"])

# 待ち合わせ。ポーリング間隔と回数を明示して無限待ちを防ぐ
print(client.waiter_names)  # 例: ['bucket_exists', 'object_exists', ...]
client.get_waiter("object_exists").wait(
    Bucket="example-bucket",
    Key="logs/2026/09/report.json",
    WaiterConfig={"Delay": 5, "MaxAttempts": 12},
)

waiterは既定のまま使うと、想定より長く待ち続けることがあります。バッチの中で使うならWaiterConfigで上限を切り、超過時のWaiterErrorを自分の異常系として扱ってください。

リトライ既定legacyの見落としとstandard・adaptiveの設定値

ここが最も誤解の多い箇所です。boto3のリトライは、何も設定しなければ古いlegacyモードで動きます。standardが既定だと思い込んだまま流量制御を設計すると、想定と違う回数で再送されます。

legacy5回・standard3回・adaptive3回で変わる既定の試行回数

リトライのガイドが示す既定の最大試行回数は、legacyが5回、standardとadaptiveが3回です。いずれも初回リクエストを含む数字です。legacyは再試行の対象とするエラーの範囲が狭く、standardはより多くのスロットリング系エラーを拾います。adaptiveはクライアント側のレート制限を加えた実験的な位置づけです。

モード 既定の最大試行回数 選ぶ場面
legacy(既定) 5(初回を含む) 既存挙動を変えたくない保守対象
standard 3(初回を含む) 新規実装。他言語SDKと挙動を揃えたい場合
adaptive 3(初回を含む) スロットリングが常態化した高頻度バッチ

新規実装ではstandardを明示指定してください。他言語のSDKと再送の考え方が揃い、障害時の挙動を説明しやすくなります。

max_attemptsとtotal_max_attemptsで数え方が変わる設定の罠

同じmax_attemptsという名前でも、設定する場所で意味が変わります。AWS設定ファイルや環境変数のmax_attemptsは初回を含む総試行回数、Configオブジェクトのmax_attemptsは初回を除いた再試行回数です。公式ドキュメントは、混乱を避けるためConfigではtotal_max_attemptsを使うよう推奨しています。

import boto3
from botocore.config import Config

config = Config(
    retries={"total_max_attempts": 4, "mode": "standard"},  # 初回+3回の再送
    connect_timeout=5,
    read_timeout=30,
)

ddb = boto3.client("dynamodb", region_name="ap-northeast-1", config=config)

タイムアウトも同じConfigで渡せます。既定の読み取りタイムアウトは60秒あるため、API Gateway経由の同期処理では先に呼び出し側が切れます。再送回数とタイムアウトは必ず組で決めてください。

ClientErrorの分岐とRequestIdを残すエラーハンドリングの型

AWSのAPIエラーは、Pythonの例外クラスとしてすべてが静的に定義されているわけではありません。エラーハンドリングのガイドは、あらゆるサービス例外を捕まえる方法としてbotocore.exceptions.ClientErrorを挙げています。

response[‘Error’][‘Code’]分岐とRequestIdのログ記録

エラーレスポンスはError.CodeError.MessageResponseMetadata.RequestIdResponseMetadata.HTTPStatusCodeという構造です。AWSサポートへ問い合わせる際に必要になるのはRequestIdなので、ログへ必ず落とします。

import logging
import boto3
import botocore

logger = logging.getLogger(__name__)
client = boto3.client("sqs", region_name="ap-northeast-1")

try:
    client.send_message(QueueUrl=queue_url, MessageBody="payload")
except botocore.exceptions.ClientError as err:
    code = err.response["Error"]["Code"]
    meta = err.response["ResponseMetadata"]
    logger.warning(
        "sqs send failed code=%s status=%s request_id=%s msg=%s",
        code, meta["HTTPStatusCode"], meta["RequestId"], err.response["Error"]["Message"],
    )
    if code not in ("InternalError", "ServiceUnavailable"):
        raise

再送すべきエラーとそうでないエラーを、コード文字列で切り分けるのがこの型の要点です。権限不足のAccessDeniedを再送しても結果は変わりません。握りつぶさず、そのまま上位へ投げます。

client.exceptionsで個別例外を捕まえるときの適用範囲と限界

サービス固有の例外はclient.exceptions.LimitExceededExceptionのように動的に参照できます。resource経由で参照する場合の経路はclient.meta.client.exceptionsです。読みやすい半面、クライアントのインスタンスに紐づくため、モジュール先頭のexcept句へ書けない制約があります。

実装の方針としては、まずClientErrorで受けてコードで分岐し、頻出する1つか2つだけを個別例外に切り出す形が保守しやすい落としどころです。Bedrockのように例外の種類が多いAPIでは、Converse APIをboto3で呼ぶ実装のように、サービスごとの例外と必要なIAM権限をセットで押さえておくと切り分けが早くなります。

boto3を採用しない場面とAWS CLI・他言語SDKへ振り分ける条件

受託開発の現場でboto3のコードを書くかどうかは、その処理を何回実行するかで決めています。ここは判断を言い切ります。

一度きりの運用操作でboto3を書かずAWS CLIに寄せる判断条件

次の3条件がそろう作業に、boto3のスクリプトを書くのは過剰です。実行が一度きり、対象リソースが数十件程度、実行者が手元のシェルにいる。この場合はAWS CLIと--query(同じJMESPath)で片付きます。コードにするとレビューとリポジトリ管理の費用が発生し、次に読む人が実行環境ごと再現しなければならなくなります。

逆に、定期実行する、実行ログを残す必要がある、条件分岐がある、のいずれかに当たるならboto3で書きます。判断の境界は処理の複雑さではなく、再現と監査が要るかどうかに置いてください。LambdaやDynamoDBと組み合わせる定期処理の全体像は、Lambda・DynamoDB・API GatewayでREST APIを作る手順が参考になります。

ブラウザ主体の構成でJavaScript SDKへ寄せるときの線引き

フロントエンドがReactやNext.jsで、サーバー側処理もNode.jsに寄っている構成では、AWSアクセスだけをPythonに分けると運用単位が2つに増えます。この場合はboto3を使わず、AWS SDK for JavaScript v3の使い方で統一するほうが、依存管理も権限設計も1系統で済みます。

Pythonを選ぶ理由が明確なのは、機械学習や自然言語処理のライブラリと同じプロセスでAWSを呼ぶ場合です。たとえばAmazon Translateをboto3から呼ぶ実装のように、前処理と後処理がPython側にあるならboto3で一本化します。言語選定に迷う段階の相談や、複数アカウント構成の設計そのものは、インフラ構築(AWS・Google Cloud・Azure)の窓口で受けています。

よくある質問

boto3の導入と運用でよく挙がる5つの質問に、公式ドキュメントの記載を根拠に答えます。

boto3とは何ですか?

AWSが提供するPython用のSDK(AWS SDK for Python)です。S3やEC2、DynamoDBなどのAWS APIを、Pythonの関数呼び出しとして書けます。内部では下位ライブラリのbotocoreがリクエストの署名や送信を担っており、AWS CLIも同じbotocoreの上に立っています。2026年9月時点の公式ドキュメントが示す版は1.43.97です。

boto3のインストール方法と対応するPythonのバージョンは?

pip install boto3で入ります。setup.pyのpython_requires>= 3.10で、分類子には3.10から3.14までが記載されています。Python 3.9のサポートは2026年4月29日に終了しました。本番用の依存指定ではboto3==1.43.97のように版を固定し、開発機とCIとデプロイ先で同じ版が入る状態にしてください。

clientとresourceはどちらを使うべきですか?

新規実装はclientです。公式ドキュメントに「resourcesインターフェースへ新機能を追加する予定はない」と明記されており、新しいサービス機能はclientからしか使えません。既存のresourceコードは動き続けるため、全面的な書き換えは不要です。新機能が必要になった箇所だけclientへ寄せる進め方で足ります。

AWS Lambdaに同梱されているboto3をそのまま使ってよいですか?

動作確認だけなら使えます。ただしAWSの公式ドキュメントは、ランタイムに含まれるSDKの版がランタイムのバージョンとリージョンによって変わると説明しています。新しいAPIパラメータを使うコードでは、デプロイパッケージかLayerに自分で固定した版を含めてください。print(boto3.__version__)を1度実行して、実際に読み込まれている版を確かめるのが確実です。

認証情報はどこに置くのが安全ですか?

AWS上で動かすなら、アクセスキーを置かず実行ロールに任せます。Lambda・ECS・EC2ではコンテナ認証情報プロバイダやインスタンスメタデータが探索順序の末尾に置かれ、明示的な認証情報が無い場合に使われるためです。ローカル開発では共有認証ファイルのプロファイルを使い、環境変数へアクセスキーを残さないでください。環境変数のほうが先に評価され、意図しないアカウントへ繋がります。

関連記事

資料請求

RELATED POSTS 関連記事