DynamoDB
Overview
Dynamodb is a data platform used to store and query analytical or operational data. Learn more in the official Dynamodb documentation.
The DataHub integration for Dynamodb covers core metadata entities such as datasets/tables/views, schema fields, and containers. It also captures tags and stateful deletion detection.
Concept Mapping
| Source Concept | DataHub Concept | Notes |
|---|---|---|
"dynamodb" | Data Platform | |
| DynamoDB Table | Dataset |
Module dynamodb
Important Capabilities
| Capability | Status | Notes |
|---|---|---|
| Column-level Lineage | ✅ | Optionally enabled via include_s3_export_lineage with include_s3_export_column_lineage. |
| Detect Deleted Entities | ✅ | Enabled by default via stateful ingestion. |
| Extract Tags | ✅ | Optionally enabled via extract_table_tags to extract dynamoDB table tags as DataHub tags. |
| Platform Instance | ✅ | By default, platform_instance will use the AWS account id. |
| Table-Level Lineage | ✅ | Optionally enabled via include_s3_export_lineage for DynamoDB Export to S3 destinations. |
Overview
The dynamodb module ingests metadata from Dynamodb into DataHub. It is intended for production ingestion workflows and module-specific capabilities are documented below.
Prerequisites
Starting v0.13.3, aws_region is required. The connector no longer loops through all AWS regions and only uses the region specified in your recipe.
Attach the AmazonDynamoDBReadOnlyAccess policy to a user in your AWS account, then create an API access key and secret. The following privileges are required:
dynamodb:ListTables
dynamodb:DescribeTable
dynamodb:Scan
dynamodb:ListTagsOfResource
dynamodb:Scan is required because DynamoDB does not return schema information in dynamodb:DescribeTable. The connector samples a few values to infer the schema.
dynamodb:ListTagsOfResource is required only when extract_table_tags is enabled to extract DynamoDB table tags.
When include_s3_export_lineage is enabled, also grant:
dynamodb:ListExports
dynamodb:DescribeExport
These permissions only read existing Export to S3 job metadata. The connector does not start or manage exports.
Install the Plugin
pip install 'acryl-datahub[dynamodb]'
Starter Recipe
Check out the following recipe to get started with ingestion! See below for full configuration options.
For general pointers on writing and running a recipe, see our main recipe guide.
source:
type: dynamodb
config:
aws_access_key_id: "${AWS_ACCESS_KEY_ID}"
aws_secret_access_key: "${AWS_SECRET_ACCESS_KEY}"
aws_region: "${AWS_REGION}"
# Number of items to sample from each table for schema inference (default: 100)
# schema_sampling_size: 100
# Discover existing DynamoDB Export to S3 jobs and emit COPY lineage to S3.
# Does not start exports — only reads ListExports/DescribeExport metadata.
# include_s3_export_lineage: true
# If there are items that have most representative fields of the table, users could use the
# `include_table_item` option to provide a list of primary keys of the table in dynamodb format.
# For each `region.table`, the list of primary keys can be at most 100.
# We include these items in addition to the first 100 items in the table when we scan it.
#
# include_table_item:
# region.table_name:
# [
# {
# "partition_key_name": { "attribute_type": "attribute_value" },
# "sort_key_name": { "attribute_type": "attribute_value" },
# },
# ]
sink:
# sink configs
Config Details
- Options
- Schema
Note that a . is used to denote nested fields in the YAML recipe.
| Field | Description |
|---|---|
aws_access_key_id One of string, null | AWS access key ID. Can be auto-detected, see the AWS boto3 docs for details. Default: None |
aws_advanced_config object | Advanced AWS configuration options. These are passed directly to botocore.config.Config. |
aws_endpoint_url One of string, null | The AWS service endpoint. This is normally constructed automatically, but can be overridden here. Default: None |
aws_profile One of string, null | The named profile to use from AWS credentials. Falls back to default profile if not specified and no access keys provided. Profiles are configured in ~/.aws/credentials or ~/.aws/config. Default: None |
aws_proxy One of string, null | A set of proxy configs to use with AWS. See the botocore.config docs for details. Default: None |
aws_region One of string, null | AWS region code. Default: None |
aws_retry_mode Enum | One of: "legacy", "standard", "adaptive" Default: standard |
aws_retry_num integer | Number of times to retry failed AWS requests. See the botocore.retry docs for details. Default: 5 |
aws_secret_access_key One of string(password), null | AWS secret access key. Can be auto-detected, see the AWS boto3 docs for details. Default: None |
aws_session_token One of string(password), null | AWS session token. Can be auto-detected, see the AWS boto3 docs for details. Default: None |
extract_table_tags boolean | When enabled, tags associated with DynamoDB tables in AWS will be emitted as DataHub tags. Tags are applied using OVERWRITE mode, meaning any existing tags including tags manually added or modified from the UI will be replaced. Use with caution. Default: False |
include_s3_export_column_lineage boolean | When include_s3_export_lineage is enabled, also emit column-level COPY lineage inferred from the DynamoDB table's schema. With a DataHub connection and the S3 export dataset already in DataHub, only fields that match its schema (case-insensitive) are linked. Without a connection, or when the dataset has no schema in DataHub, the DynamoDB field paths are used as-is. If the schema cannot be read, only table-level lineage is emitted. Off by default: native Export to S3 writes DynamoDB JSON/Ion, whose field paths often differ from the connector's flattened schema. Default: False |
include_s3_export_lineage boolean | When enabled, discovers existing DynamoDB Export to S3 jobs via ListExports/DescribeExport and emits COPY lineage from each DynamoDB table to its S3 destination. Does not start or manage exports — only reads export metadata, which AWS keeps for about 90 days. Requires dynamodb:ListExports and dynamodb:DescribeExport. Default: False |
max_exports_per_table integer | When include_s3_export_lineage is enabled, the maximum number of completed exports to describe per table. A table exported frequently accumulates many export ARNs over the ~90-day retention window that nearly all resolve to the same destination; this bounds the DescribeExport calls. Exports are described in the order ListExports returns them; AWS does not document that ordering, so which exports are kept when a table exceeds this limit is not guaranteed. Default: 50 |
max_schema_size integer | Maximum number of fields to include in the schema. Default: 300 |
platform_instance One of string, null | The instance of the platform that all assets produced by this recipe belong to. This should be unique within the platform. See https://docs.datahub.com/docs/platform-instances/ for more details. Default: None |
read_timeout number | The timeout for reading from the connection (in seconds). Default: 60 |
s3_export_platform_instance One of string, null | When include_s3_export_lineage is enabled, the platform_instance to stamp on the S3 export dataset URNs. Set this to match the platform_instance used by the S3 source that ingests the export bucket, otherwise the lineage edges point at an S3 URN that does not exist. Default: None |
schema_sampling_size integer | Number of items to sample from each table for schema inference. This controls how many items are scanned to determine the table's schema structure. Default: 100 |
env string | The environment that all assets produced by this connector belong to Default: PROD |
aws_role One of string, array, null | AWS roles to assume. If using the string format, the role ARN can be specified directly. If using the object format, the role can be specified in the RoleArn field and additional available arguments are the same as boto3's STS.Client.assume_role. Default: None |
aws_role.union One of string, AwsAssumeRoleConfig | |
aws_role.union.RoleArn ❓ string | ARN of the role to assume. |
aws_role.union.ExternalId One of string, null | External ID to use when assuming the role. Default: None |
database_pattern AllowDenyPattern | A class to store allow deny regexes. Patterns are matched against the start of the string only, not the entire string - a pattern does not need to match to the end to be considered a match. For example, the pattern "prod" matches "prod", "prod_east", and "production". To require an exact match, anchor your pattern explicitly, e.g. "^prod$". |
database_pattern.ignoreCase One of boolean, null | Whether to ignore case sensitivity during pattern matching. Default: True |
domain map(str,AllowDenyPattern) | A class to store allow deny regexes. Patterns are matched against the start of the string only, not the entire string - a pattern does not need to match to the end to be considered a match. For example, the pattern "prod" matches "prod", "prod_east", and "production". To require an exact match, anchor your pattern explicitly, e.g. "^prod$". |
domain. key.allowarray | List of regex patterns to include in ingestion. Patterns match from the start of the string only, not the entire string - anchor with '^...$' for an exact match, e.g. '^prod$'. Default: ['.*'] |
domain. key.allow.stringstring | |
domain. key.ignoreCaseOne of boolean, null | Whether to ignore case sensitivity during pattern matching. Default: True |
domain. key.denyarray | List of regex patterns to exclude from ingestion. Patterns match from the start of the string only, not the entire string - anchor with '^...$' for an exact match, e.g. '^prod$'. Default: [] |
domain. key.deny.stringstring | |
include_table_item One of array, null | [Advanced] The primary keys of items of a table in dynamodb format the user would like to include in schema. Refer "Advanced Configurations" section for more details Default: None |
include_table_item. key.objectobject | |
table_pattern AllowDenyPattern | A class to store allow deny regexes. Patterns are matched against the start of the string only, not the entire string - a pattern does not need to match to the end to be considered a match. For example, the pattern "prod" matches "prod", "prod_east", and "production". To require an exact match, anchor your pattern explicitly, e.g. "^prod$". |
table_pattern.ignoreCase One of boolean, null | Whether to ignore case sensitivity during pattern matching. Default: True |
classification ClassificationConfig | |
classification.enabled boolean | Whether classification should be used to auto-detect glossary terms Default: False |
classification.info_type_to_term map(str,string) | |
classification.max_workers integer | Number of worker processes to use for classification. Set to 1 to disable. Default: 4 |
classification.sample_size integer | Number of sample values used for classification. Default: 100 |
classification.classifiers array | Classifiers to use to auto-detect glossary terms. If more than one classifier, infotype predictions from the classifier defined later in sequence take precedance. Default: [{'type': 'datahub', 'config': None}] |
classification.classifiers.DynamicTypedClassifierConfig DynamicTypedClassifierConfig | |
classification.classifiers.DynamicTypedClassifierConfig.type ❓ string | The type of the classifier to use. The built-in datahub classifier has been removed; register a custom classifier and reference its type here. |
classification.classifiers.DynamicTypedClassifierConfig.config One of object, null | The configuration required for initializing the classifier. If not specified, uses defaults for classifer type. Default: None |
classification.column_pattern AllowDenyPattern | A class to store allow deny regexes. Patterns are matched against the start of the string only, not the entire string - a pattern does not need to match to the end to be considered a match. For example, the pattern "prod" matches "prod", "prod_east", and "production". To require an exact match, anchor your pattern explicitly, e.g. "^prod$". |
classification.column_pattern.ignoreCase One of boolean, null | Whether to ignore case sensitivity during pattern matching. Default: True |
classification.table_pattern AllowDenyPattern | A class to store allow deny regexes. Patterns are matched against the start of the string only, not the entire string - a pattern does not need to match to the end to be considered a match. For example, the pattern "prod" matches "prod", "prod_east", and "production". To require an exact match, anchor your pattern explicitly, e.g. "^prod$". |
classification.table_pattern.ignoreCase One of boolean, null | Whether to ignore case sensitivity during pattern matching. Default: True |
stateful_ingestion One of StatefulStaleMetadataRemovalConfig, null | Default: None |
stateful_ingestion.enabled boolean | Whether or not to enable stateful ingest. Default: True if a pipeline_name is set and either a datahub-rest sink or datahub_api is specified, otherwise False Default: False |
stateful_ingestion.fail_safe_threshold number | Prevents large amount of soft deletes & the state from committing from accidental changes to the source configuration if the relative change percent in entities compared to the previous state is above the 'fail_safe_threshold'. Default: 75.0 |
stateful_ingestion.remove_stale_metadata boolean | Soft-deletes the entities present in the last successful run but missing in the current run with stateful_ingestion enabled. Default: True |
The JSONSchema for this configuration is inlined below.
{
"$defs": {
"AllowDenyPattern": {
"additionalProperties": false,
"description": "A class to store allow deny regexes.\n\nPatterns are matched against the start of the string only, not the entire\nstring - a pattern does not need to match to the end to be considered a match.\nFor example, the pattern \"prod\" matches \"prod\", \"prod_east\", and \"production\".\nTo require an exact match, anchor your pattern explicitly, e.g. \"^prod$\".",
"properties": {
"allow": {
"default": [
".*"
],
"description": "List of regex patterns to include in ingestion. Patterns match from the start of the string only, not the entire string - anchor with '^...$' for an exact match, e.g. '^prod$'.",
"items": {
"type": "string"
},
"title": "Allow",
"type": "array"
},
"deny": {
"default": [],
"description": "List of regex patterns to exclude from ingestion. Patterns match from the start of the string only, not the entire string - anchor with '^...$' for an exact match, e.g. '^prod$'.",
"items": {
"type": "string"
},
"title": "Deny",
"type": "array"
},
"ignoreCase": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"default": true,
"description": "Whether to ignore case sensitivity during pattern matching.",
"title": "Ignorecase"
}
},
"title": "AllowDenyPattern",
"type": "object"
},
"AwsAssumeRoleConfig": {
"additionalProperties": true,
"properties": {
"RoleArn": {
"description": "ARN of the role to assume.",
"title": "Rolearn",
"type": "string"
},
"ExternalId": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "External ID to use when assuming the role.",
"title": "Externalid"
}
},
"required": [
"RoleArn"
],
"title": "AwsAssumeRoleConfig",
"type": "object"
},
"ClassificationConfig": {
"additionalProperties": false,
"properties": {
"enabled": {
"default": false,
"description": "Whether classification should be used to auto-detect glossary terms",
"title": "Enabled",
"type": "boolean"
},
"sample_size": {
"default": 100,
"description": "Number of sample values used for classification.",
"title": "Sample Size",
"type": "integer"
},
"max_workers": {
"default": 4,
"description": "Number of worker processes to use for classification. Set to 1 to disable.",
"title": "Max Workers",
"type": "integer"
},
"table_pattern": {
"$ref": "#/$defs/AllowDenyPattern",
"default": {
"allow": [
".*"
],
"deny": [],
"ignoreCase": true
},
"description": "Regex patterns to filter tables for classification. This is used in combination with other patterns in parent config. Specify regex to match the entire table name in `database.schema.table` format. e.g. to match all tables starting with customer in Customer database and public schema, use the regex 'Customer.public.customer.*'"
},
"column_pattern": {
"$ref": "#/$defs/AllowDenyPattern",
"default": {
"allow": [
".*"
],
"deny": [],
"ignoreCase": true
},
"description": "Regex patterns to filter columns for classification. This is used in combination with other patterns in parent config. Specify regex to match the column name in `database.schema.table.column` format."
},
"info_type_to_term": {
"additionalProperties": {
"type": "string"
},
"default": {},
"description": "Optional mapping to provide glossary term identifier for info type",
"title": "Info Type To Term",
"type": "object"
},
"classifiers": {
"default": [
{
"type": "datahub",
"config": null
}
],
"description": "Classifiers to use to auto-detect glossary terms. If more than one classifier, infotype predictions from the classifier defined later in sequence take precedance.",
"items": {
"$ref": "#/$defs/DynamicTypedClassifierConfig"
},
"title": "Classifiers",
"type": "array"
}
},
"title": "ClassificationConfig",
"type": "object"
},
"DynamicTypedClassifierConfig": {
"additionalProperties": false,
"properties": {
"type": {
"description": "The type of the classifier to use. The built-in `datahub` classifier has been removed; register a custom classifier and reference its type here.",
"title": "Type",
"type": "string"
},
"config": {
"anyOf": [
{},
{
"type": "null"
}
],
"default": null,
"description": "The configuration required for initializing the classifier. If not specified, uses defaults for classifer type.",
"title": "Config"
}
},
"required": [
"type"
],
"title": "DynamicTypedClassifierConfig",
"type": "object"
},
"StatefulStaleMetadataRemovalConfig": {
"additionalProperties": false,
"description": "Base specialized config for Stateful Ingestion with stale metadata removal capability.",
"properties": {
"enabled": {
"default": false,
"description": "Whether or not to enable stateful ingest. Default: True if a pipeline_name is set and either a datahub-rest sink or `datahub_api` is specified, otherwise False",
"title": "Enabled",
"type": "boolean"
},
"remove_stale_metadata": {
"default": true,
"description": "Soft-deletes the entities present in the last successful run but missing in the current run with stateful_ingestion enabled.",
"title": "Remove Stale Metadata",
"type": "boolean"
},
"fail_safe_threshold": {
"default": 75.0,
"description": "Prevents large amount of soft deletes & the state from committing from accidental changes to the source configuration if the relative change percent in entities compared to the previous state is above the 'fail_safe_threshold'.",
"maximum": 100.0,
"minimum": 0.0,
"title": "Fail Safe Threshold",
"type": "number"
}
},
"title": "StatefulStaleMetadataRemovalConfig",
"type": "object"
}
},
"additionalProperties": false,
"properties": {
"aws_access_key_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "AWS access key ID. Can be auto-detected, see [the AWS boto3 docs](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html) for details.",
"title": "Aws Access Key Id"
},
"aws_secret_access_key": {
"anyOf": [
{
"format": "password",
"type": "string",
"writeOnly": true
},
{
"type": "null"
}
],
"default": null,
"description": "AWS secret access key. Can be auto-detected, see [the AWS boto3 docs](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html) for details.",
"title": "Aws Secret Access Key"
},
"aws_session_token": {
"anyOf": [
{
"format": "password",
"type": "string",
"writeOnly": true
},
{
"type": "null"
}
],
"default": null,
"description": "AWS session token. Can be auto-detected, see [the AWS boto3 docs](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html) for details.",
"title": "Aws Session Token"
},
"aws_role": {
"anyOf": [
{
"type": "string"
},
{
"items": {
"anyOf": [
{
"type": "string"
},
{
"$ref": "#/$defs/AwsAssumeRoleConfig"
}
]
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "AWS roles to assume. If using the string format, the role ARN can be specified directly. If using the object format, the role can be specified in the RoleArn field and additional available arguments are the same as [boto3's STS.Client.assume_role](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sts.html?highlight=assume_role#STS.Client.assume_role).",
"title": "Aws Role"
},
"aws_profile": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The [named profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) to use from AWS credentials. Falls back to default profile if not specified and no access keys provided. Profiles are configured in ~/.aws/credentials or ~/.aws/config.",
"title": "Aws Profile"
},
"aws_region": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "AWS region code.",
"title": "Aws Region"
},
"aws_endpoint_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The AWS service endpoint. This is normally [constructed automatically](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/core/session.html), but can be overridden here.",
"title": "Aws Endpoint Url"
},
"aws_proxy": {
"anyOf": [
{
"additionalProperties": {
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"description": "A set of proxy configs to use with AWS. See the [botocore.config](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html) docs for details.",
"title": "Aws Proxy"
},
"aws_retry_num": {
"default": 5,
"description": "Number of times to retry failed AWS requests. See the [botocore.retry](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html) docs for details.",
"title": "Aws Retry Num",
"type": "integer"
},
"aws_retry_mode": {
"default": "standard",
"description": "Retry mode to use for failed AWS requests. See the [botocore.retry](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html) docs for details.",
"enum": [
"legacy",
"standard",
"adaptive"
],
"title": "Aws Retry Mode",
"type": "string"
},
"read_timeout": {
"default": 60,
"description": "The timeout for reading from the connection (in seconds).",
"title": "Read Timeout",
"type": "number"
},
"aws_advanced_config": {
"additionalProperties": true,
"description": "Advanced AWS configuration options. These are passed directly to [botocore.config.Config](https://botocore.amazonaws.com/v1/documentation/api/latest/reference/config.html).",
"title": "Aws Advanced Config",
"type": "object"
},
"env": {
"default": "PROD",
"description": "The environment that all assets produced by this connector belong to",
"title": "Env",
"type": "string"
},
"database_pattern": {
"$ref": "#/$defs/AllowDenyPattern",
"default": {
"allow": [
".*"
],
"deny": [],
"ignoreCase": true
},
"description": "regex patterns for databases to filter in ingestion."
},
"table_pattern": {
"$ref": "#/$defs/AllowDenyPattern",
"default": {
"allow": [
".*"
],
"deny": [],
"ignoreCase": true
},
"description": "Regex patterns for tables to filter in ingestion. The table name format is 'region.table'"
},
"classification": {
"$ref": "#/$defs/ClassificationConfig",
"default": {
"enabled": false,
"sample_size": 100,
"max_workers": 4,
"table_pattern": {
"allow": [
".*"
],
"deny": [],
"ignoreCase": true
},
"column_pattern": {
"allow": [
".*"
],
"deny": [],
"ignoreCase": true
},
"info_type_to_term": {},
"classifiers": [
{
"config": null,
"type": "datahub"
}
]
},
"description": "For details, refer to [Classification](../../../../metadata-ingestion/docs/dev_guides/classification.md)."
},
"stateful_ingestion": {
"anyOf": [
{
"$ref": "#/$defs/StatefulStaleMetadataRemovalConfig"
},
{
"type": "null"
}
],
"default": null
},
"platform_instance": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The instance of the platform that all assets produced by this recipe belong to. This should be unique within the platform. See https://docs.datahub.com/docs/platform-instances/ for more details.",
"title": "Platform Instance"
},
"domain": {
"additionalProperties": {
"$ref": "#/$defs/AllowDenyPattern"
},
"default": {},
"description": "regex patterns for tables to filter to assign domain_key. ",
"title": "Domain",
"type": "object"
},
"include_table_item": {
"anyOf": [
{
"additionalProperties": {
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
"type": "object"
},
{
"type": "null"
}
],
"default": null,
"description": "[Advanced] The primary keys of items of a table in dynamodb format the user would like to include in schema. Refer \"Advanced Configurations\" section for more details",
"title": "Include Table Item"
},
"max_schema_size": {
"default": 300,
"description": "Maximum number of fields to include in the schema.",
"exclusiveMinimum": 0,
"title": "Max Schema Size",
"type": "integer"
},
"schema_sampling_size": {
"default": 100,
"description": "Number of items to sample from each table for schema inference. This controls how many items are scanned to determine the table's schema structure.",
"exclusiveMinimum": 0,
"title": "Schema Sampling Size",
"type": "integer"
},
"extract_table_tags": {
"default": false,
"description": "When enabled, tags associated with DynamoDB tables in AWS will be emitted as DataHub tags. Tags are applied using OVERWRITE mode, meaning any existing tags including tags manually added or modified from the UI will be replaced. Use with caution.",
"title": "Extract Table Tags",
"type": "boolean"
},
"include_s3_export_lineage": {
"default": false,
"description": "When enabled, discovers existing DynamoDB Export to S3 jobs via ListExports/DescribeExport and emits COPY lineage from each DynamoDB table to its S3 destination. Does not start or manage exports \u2014 only reads export metadata, which AWS keeps for about 90 days. Requires dynamodb:ListExports and dynamodb:DescribeExport.",
"title": "Include S3 Export Lineage",
"type": "boolean"
},
"include_s3_export_column_lineage": {
"default": false,
"description": "When `include_s3_export_lineage` is enabled, also emit column-level COPY lineage inferred from the DynamoDB table's schema. With a DataHub connection and the S3 export dataset already in DataHub, only fields that match its schema (case-insensitive) are linked. Without a connection, or when the dataset has no schema in DataHub, the DynamoDB field paths are used as-is. If the schema cannot be read, only table-level lineage is emitted. Off by default: native Export to S3 writes DynamoDB JSON/Ion, whose field paths often differ from the connector's flattened schema.",
"title": "Include S3 Export Column Lineage",
"type": "boolean"
},
"max_exports_per_table": {
"default": 50,
"description": "When `include_s3_export_lineage` is enabled, the maximum number of completed exports to describe per table. A table exported frequently accumulates many export ARNs over the ~90-day retention window that nearly all resolve to the same destination; this bounds the DescribeExport calls. Exports are described in the order ListExports returns them; AWS does not document that ordering, so which exports are kept when a table exceeds this limit is not guaranteed.",
"exclusiveMinimum": 0,
"title": "Max Exports Per Table",
"type": "integer"
},
"s3_export_platform_instance": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "When `include_s3_export_lineage` is enabled, the `platform_instance` to stamp on the S3 export dataset URNs. Set this to match the `platform_instance` used by the S3 source that ingests the export bucket, otherwise the lineage edges point at an S3 URN that does not exist.",
"title": "S3 Export Platform Instance"
}
},
"title": "DynamoDBConfig",
"type": "object"
}
Capabilities
Use the Important Capabilities table above as the source of truth for supported features and whether additional configuration is required.
Using schema_sampling_size config
By default, the connector samples 100 items from each table to infer the schema. You can adjust this using the schema_sampling_size configuration option if you need more comprehensive schema coverage:
# Sample 500 items instead of default 100
schema_sampling_size: 500
Using include_table_item config
If there are items that have most representative fields of the table, users could use the include_table_item option to provide a list of primary keys of the table in dynamodb format. We include these items in addition to the items sampled based on schema_sampling_size (default 100) when we scan the table.
Take AWS DynamoDB Developer Guide Example tables and data as an example, if a account has a table Reply in the us-west-2 region with composite primary key Id and ReplyDateTime, users can use include_table_item to include 2 items as following:
Example:
# The table name should be in the format of region.table_name
# The primary keys should be in the DynamoDB format
include_table_item:
us-west-2.Reply:
[
{
"ReplyDateTime": { "S": "2015-09-22T19:58:22.947Z" },
"Id": { "S": "Amazon DynamoDB#DynamoDB Thread 1" },
},
{
"ReplyDateTime": { "S": "2015-10-05T19:58:22.947Z" },
"Id": { "S": "Amazon DynamoDB#DynamoDB Thread 2" },
},
]
DynamoDB Export to S3 lineage
Set include_s3_export_lineage: true to discover existing DynamoDB Export to S3 jobs and emit COPY lineage from each DynamoDB table to its S3 destination (s3://bucket/prefix).
By default this emits table-level COPY edges only. Set include_s3_export_column_lineage: true to also emit column-level lineage inferred from the DynamoDB table's schema. When the recipe has a DataHub connection and the S3 export dataset already exists in DataHub, only fields that match its schema (case-insensitive) are linked. Without a connection, or when the dataset is not in DataHub, the inferred DynamoDB field paths are used as-is. If the schema cannot be read, only table-level lineage is emitted. Leave it off unless you know the S3 export layout matches those field paths — native Export to S3 writes DynamoDB JSON or Amazon Ion, which often does not. For a robust column-level story, ingest the downstream Glue/Iceberg tables (via the Glue source), which resolves column lineage against real schemas.
The connector only calls ListExports and DescribeExport. It does not create exports. AWS retains export task metadata for about 90 days, so exports older than that stop being returned. max_exports_per_table (default 50) bounds how many completed exports are described per table, since a frequently-exported table accumulates many export records that nearly all resolve to the same destination. AWS does not document the order ListExports returns, so when a table exceeds this limit, which exports are kept is not guaranteed; the connector reports truncation, as a warning when the described exports already reach more than one destination.
include_s3_export_lineage: true
# include_s3_export_column_lineage: true
# max_exports_per_table: 50
# s3_export_platform_instance: my-s3-instance
Lineage is written as a patch, so upstreams that other sources write to the same S3 dataset are kept. The connector only adds edges and never removes them: an export destination that ages out, column edges written before include_s3_export_column_lineage was turned off, and inferred column edges from a run without a DataHub connection all stay until you remove them.
Matching the S3 URNs. Two things must line up for these edges to join the S3 datasets you ingest separately:
- Destination path. The emitted S3 URN is the export's configured destination (
s3://bucket/prefix). DynamoDB actually writes the data one level deeper, unders3://bucket/prefix/AWSDynamoDB/{exportId}/data/…. If your S3 source ingests with apath_specpointed at that deeper data path, point it at thes3://bucket/prefixlevel (or add a matchingpath_spec) so the URNs join. - Platform instance. The S3 URN carries no
platform_instanceby default. If your S3 source ingests the export bucket with aplatform_instance, sets3_export_platform_instanceto the same value, otherwise these edges point at an S3 URN that does not exist.
When the recipe has a DataHub connection, the ingestion report lists export destinations that no other source has ingested (the dataset has no datasetProperties) under s3_export_destinations_not_in_datahub. Those edges land on an S3 entity that only carries lineage, which usually means one of the two settings above does not match your S3 source. The same list appears as an info entry in the ingestion run's structured logs. It also includes destinations the S3 source has not ingested yet, for example when the S3 recipe runs after this one. A soft-deleted S3 dataset still has datasetProperties, so it is not listed.
Exports started by Glue jobs. The Glue DynamoDB export connector (dynamodb.export: "ddb") requests a regular DynamoDB export on every job run, so those exports appear in ListExports and get COPY edges like any other. If the job sets neither dynamodb.s3.bucket nor dynamodb.s3.prefix, the export goes to the job's temporary directory (--TempDir), so the lineage points at that temporary path, and a scheduled job's exports also count against max_exports_per_table. Set dynamodb.s3.bucket and dynamodb.s3.prefix on those jobs to give the exports a stable destination.
Limitations
Module behavior is constrained by source APIs, permissions, and metadata exposed by the platform. Refer to capability notes for unsupported or conditional features.
S3 export lineage is limited to DynamoDB's native Export to S3 feature (DynamoDB JSON or Amazon Ion — not Parquet or Iceberg). Glue/Spark jobs that convert exports to Parquet or Iceberg are discovered by the Glue source when job scripts use connection_type: dynamodb.
Troubleshooting
If ingestion fails, validate credentials, permissions, connectivity, and scope filters first. Then review ingestion logs for source-specific errors and adjust configuration accordingly.
If S3 export lineage is missing, confirm include_s3_export_lineage is enabled, the IAM principal can call dynamodb:ListExports and dynamodb:DescribeExport, and a COMPLETED export exists for the table within the last 90 days.
Code Coordinates
- Class Name:
datahub.ingestion.source.dynamodb.dynamodb.DynamoDBSource - Browse on GitHub
If you've got any questions on configuring ingestion for DynamoDB, feel free to ping us on our Slack.
This page is auto-generated from the underlying source code. To make changes, please edit the relevant source files in the metadata-ingestion directory.
Tip: For quick typo fixes or documentation updates, you can click the ✏️ Edit icon directly in the GitHub UI to open a Pull Request. For larger changes and PR naming conventions, please refer to our Contributing Guide.