MaxCompute Destination
Private Beta12 minute read
The MaxCompute warehouse destination is in Private Beta. Contact Customer Success to enable it for your workspace.
Use MaxCompute as a warehouse destination to load events through an Alibaba Cloud Object Storage Service (OSS) bucket. RudderStack stages files in OSS before loading them into your MaxCompute project. For common event-to-table mappings, see Warehouse Schema; MaxCompute-specific differences are noted below.
Prepare your project and OSS bucket
- Enable Enable Schema for the MaxCompute project so it supports the three-tier project, schema, and table namespace. This upgrade is one-way and has a settling period; wait for it to finish before creating the destination. Plan the change with your MaxCompute administrator.
- Check that the project uses the V2.0 data type edition. MaxCompute V1.0 can’t represent
TIMESTAMP; a session hint doesn’t upgrade the project. Arrange a project edition upgrade before loading data if needed. - Create or select an OSS bucket in the same region as the MaxCompute project. Record the project region and endpoint. The configured endpoint must be exactly
https://service.<region>.maxcompute.aliyun.com/api, with<region>matching the project’s region. Use the same region for OSS. - Choose a new schema name for Namespace, but don’t pre-create the schema. RudderStack creates it on the first sync. This version can’t load into a schema owned by another principal.
- Choose an OSS directory path containing the bucket name and, optionally, a directory prefix, for example,
rudder-stagingorrudder-staging/rudder/events. Use that same prefix when scoping OSS access. There is no separate prefix setting.
Grant minimum-privilege access
Use role authentication unless you need AccessKey authentication. Both modes need MaxCompute project membership and a separate read role that MaxCompute assumes to load objects from OSS. Replace angle-bracketed placeholders below with the indicated RudderStack or Alibaba Cloud values.
Grant project permissions for role authentication
Create an access role for RudderStack in RAM. In its trust policy, allow the RudderStack RAM principal
acs:ram::5332290435279528:user/rudderstack-maxcompute-caller-prodand requirests:ExternalIdto equal your RudderStack workspace ID. Replace<RUDDERSTACK_WORKSPACE_ID>in this example with your workspace ID. Record the access role ARN for the MaxCompute account setup.json{ "Version": "1", "Statement": [ { "Effect": "Allow", "Principal": { "RAM": ["acs:ram::5332290435279528:user/rudderstack-maxcompute-caller-prod"] }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "<RUDDERSTACK_WORKSPACE_ID>" } } } ] }Grant the access role OSS access to the configured bucket and directory prefix.
As a MaxCompute project administrator, add the access role as a project user and grant it the following four project permissions. Replace
<account-uid>with your Alibaba Cloud account UID (not the workspace ID or the RAM user’s UID). Replace<role-name>with the name of the access role, not the read role:
ADD USER `RAM$<account-uid>:role/<role-name>`;
GRANT CreateInstance ON PROJECT <project-name> TO USER `RAM$<account-uid>:role/<role-name>`;
GRANT CreateSchema ON PROJECT <project-name> TO USER `RAM$<account-uid>:role/<role-name>`;
GRANT CreateTable ON PROJECT <project-name> TO USER `RAM$<account-uid>:role/<role-name>`;
GRANT List ON PROJECT <project-name> TO USER `RAM$<account-uid>:role/<role-name>`;Grant project permissions for AccessKey authentication
- Create an API-only RAM user and generate an AccessKey for it. Record the AccessKey ID and secret securely. Find the user’s numeric RAM user ID, labeled UID in the RAM console; the user name isn’t a substitute.
- Give the RAM user the same prefix-scoped OSS access as the access role.
- As a MaxCompute project administrator, add the RAM user by numeric RAM user ID and grant it the same four project permissions. Use your Alibaba Cloud account UID for
<account-uid>here as well:
ADD USER `RAM$<account-uid>:<ram-user-id>`;
GRANT CreateInstance ON PROJECT <project-name> TO USER `RAM$<account-uid>:<ram-user-id>`;
GRANT CreateSchema ON PROJECT <project-name> TO USER `RAM$<account-uid>:<ram-user-id>`;
GRANT CreateTable ON PROJECT <project-name> TO USER `RAM$<account-uid>:<ram-user-id>`;
GRANT List ON PROJECT <project-name> TO USER `RAM$<account-uid>:<ram-user-id>`;Adding a RAM user name instead of its numeric UID fails withODPS-0030001 … is not a valid account. A new AccessKey can also take about 15 minutes to activate; during that time, validation fails just as it does for an incorrect key. Wait for activation before troubleshooting a newly created key.
A RAM policy alone doesn’t add the role or user to the MaxCompute project. Even AliyunMaxComputeFullAccess without ADD USER fails with ODPS-0420095.
Scope OSS permissions
For the access role (or the RAM user in AccessKey mode), allow staging file writes and reads (oss:PutObject, oss:GetObject, oss:AbortMultipartUpload, and oss:ListParts) only on the configured bucket’s objects under the chosen directory prefix. For rudder-staging/rudder/events, scope the object resource to acs:oss:*:*:rudder-staging/rudder/events/*; for a bucket-only path, use acs:oss:*:*:rudder-staging/*. Allow oss:ListObjects on the bucket resource (acs:oss:*:*:rudder-staging) only with an oss:Prefix condition restricting listings to the chosen directory prefix (rudder/events/* in this example). Include the trailing slash so the policy doesn’t match sibling directories such as rudder/events-private/. For a bucket-only path, allow listing across that bucket, not other buckets. If Clean up staged files after successful sync is on, also allow oss:DeleteObject on the same object resource. Turning cleanup off removes the delete requirement. Don’t grant access to unrelated buckets or prefixes.
Create a separate read role for MaxCompute LOAD. Its RAM trust policy must trust the service principal odps.aliyuncs.com. Allow oss:GetObject on the same scoped object resource, and oss:ListObjects (restricted by the same oss:Prefix condition when a prefix is set) and oss:GetBucketInfo on that bucket resource. Enter its ARN in OSS RAM role ARN in the MaxCompute account for either account type; the access role or AccessKey user doesn’t replace it.
Configure MaxCompute in RudderStack
In the RudderStack dashboard, add MaxCompute as a warehouse destination, name it, and connect a source. During Initial setup, select or create a MaxCompute account and enter the following settings:
| Setting | Description |
|---|---|
| MaxCompute account | Choose RAM role (recommended) with MaxCompute RAM role ARN (the access role) and OSS RAM role ARN (the read role), or choose Access key with Access key ID, Access key secret, and OSS RAM role ARN. Credentials are configured in the account picker. |
| Project | Enter the MaxCompute project where RudderStack will create the schema and tables. |
| Region | Use the MaxCompute project’s region. The OSS bucket must be in the same region. |
| MaxCompute endpoint | Enter the project’s exact endpoint, https://service.<region>.maxcompute.aliyun.com/api, where <region> matches Region. |
OSS directory path (directoryPath) | Enter the bucket name, optionally followed by a directory prefix, such as rudder-staging/rudder/events. Files are staged under that prefix. The creation-time connection test uses the same path, so a prefix-scoped OSS policy can pass. There is no separate prefix field. |
| Namespace | Enter the schema name that RudderStack will create on the first sync. Use lowercase letters, digits, and single underscores; start with a letter. Digits must form their own segment: rudder_events_2 is valid, but rudder_events2 isn’t. Don’t create this schema beforehand. |
| Clean up staged files after successful sync | On by default. After a successful load, RudderStack deletes that sync’s staging and load files. The creation-time connection test checks OSS delete permission when this setting is on. Turn it off if you don’t grant oss:DeleteObject; manage file retention yourself. |
| Skip views creation | Choose whether RudderStack creates deduplication views for the tables. |
| Partition column | Choose Ingestion time (default), Loaded at, Received at, Timestamp, Sent at, or Original timestamp. |
Partition type (partitionType) | Choose Day (default) or Hour. See the partition limits before choosing hourly partitions. |
Namespace, skip views creation, partition column, and partition type are fixed at creation. Choose them before saving the destination; you can’t change them later.
Skip Users table and Skip Tracks table are under Configuration settings → Warehouse settings and can be changed later. Skip Users table is on by default; identify events still load into identifies. Turn it off to maintain a users table with carry-forward traits. Skip Tracks table is off by default.
Verify the connection and first sync
Run the connection test when creating the destination. It validates OSS access first, then MaxCompute access and a test load. With cleanup enabled, it checks OSS delete access. Confirm that the first sync creates the schema and tables and that rows appear in identifies after sending an identify event. Check Live Events or the destination’s Syncs tab for upload status. The test can leave one small OSS object even when the connection succeeds; see the test-file FAQ.
How RudderStack creates the schema
RudderStack creates a schema in your MaxCompute project with the name set in the Namespace field. The namespace is required for MaxCompute and can’t be changed after you create the destination.
See the Warehouse Schema guide for details on the tables and columns RudderStack creates.
RudderStack creates every MaxCompute table as an auto-partitioned table. Unless Skip views creation is on, it also creates a deduplication view for each table.
Partitioned tables
RudderStack creates auto-partitioned tables with a single partition key, pt. MaxCompute fills pt for every row by truncating the Partition column to the Partition type, so you can filter on pt to query a subset of data:
| Setting | Options | Example pt value |
|---|---|---|
| Partition column | Ingestion time (default), Loaded at, Received at, Timestamp, Sent at, Original timestamp | n/a |
| Partition type | Day (default) | 2026-11-11 |
| Hour | 2026-11-11 06:00:00 |
Note that:
ptvalues are in UTC.- Partition column and partition type are fixed when you create the destination.
- RudderStack reserves
pt, so an event property namedptis stored in a column named_pt. - If a later batch omits the chosen partition column, its rows still load into the
__NULL__partition. This is especially relevant for Sent at and Original timestamp, which may be absent from SDK events. Query those rows directly in the base table: the deduplication view and theuserscarry-forward read exclude them. - When querying a base table, filter on
pt(for example,WHERE pt >= '2026-11-01'). Many MaxCompute projects reject queries that read every partition; see How do I avoid a full-scan error?.
RudderStack does not discard duplicate data while loading it into MaxCompute.
Views
In addition to tables, RudderStack creates a view (<table_name>_view) for every table for deduplication purposes, unless Skip views creation is on. The view returns one row per event (id), keeping the most recently loaded one. This applies even when the duplicates are in different partitions.
Note that:
- RudderStack recommends using the corresponding view to avoid duplicate events in your query results.
- The view covers partitions from 60 days back to 2 days ahead, evaluated at query time in the session time zone. The lower edge can shift with the session offset. You don’t need an additional
ptfilter when querying a view. For older data, query the base table with aptfilter. - RudderStack recreates the view when it loads the table, so new columns appear automatically. Don’t edit the view query: your changes are overwritten on the next sync. Create your own view instead if you need a different time window.
- Rows in the
__NULL__partition aren’t included in the view. - For
rudder_discards, the view returns one row perrow_id,column_name, andtable_name.
Skip views creation
Turn on Skip views creation to disable creating views in MaxCompute. Like the partition settings, it’s fixed when you create the destination.
RudderStack recommends skipping views creation only if:
- You do not need views and want to take care of deduplication yourself.
- You have security reasons to limit access to the tables.
Users table
When Skip Users table is off (it’s on by default), RudderStack keeps each user’s latest traits in the users table. On every sync, for each user identified in that sync, RudderStack merges the user’s rows from the last 60 days with the new identify calls. It takes the latest non-null value of each trait and adds one new row for the user:
| Sync | identify traits sent | New row in users |
|---|---|---|
| 1 | email = a@x.com, plan = trial | email = a@x.com, plan = trial |
| 2 | plan = pro, company_size = 50 | email = a@x.com, plan = pro, company_size = 50 |
Note that:
- The
userstable has one row per user per sync. When views are enabled, useusers_viewto get one row per user, with their current traits. - Traits are carried forward only from the last 60 days. A user not identified in more than 60 days starts again from the new
identifycall. - Omitting a trait or sending
nulldoes not clear it; the previous value is kept.
FAQ
How do I avoid a full-scan error?
MaxCompute can return ODPS-0130071 when a base-table query doesn’t filter on partition key pt. Filter table queries on pt, or set odps.sql.allow.fullscan=true in your session if you need a full scan. Each <table>_view already filters on pt from 60 days back to two days ahead, so querying a view without an additional pt filter doesn’t trigger this guard. RudderStack’s own queries always filter on pt and never use the hint.
Why do deleted OSS files still incur storage charges?
When OSS bucket versioning is enabled, RudderStack deletes staged files without specifying a version ID. OSS creates a delete marker, but the noncurrent version remains billable. Add an OSS lifecycle rule with NoncurrentVersionExpiration and expired-delete-marker removal to clear retained versions and markers.
Which time zone applies to timestamps and partitions?
MaxCompute projects default to UTC+8 in every region. Stored timestamp values and pt partitions are correct in UTC, but displayed query results and functions such as TO_CHAR and DATETRUNC use the session time zone. For events between 16:00 and 24:00 UTC, session-local midnight doesn’t match UTC partition midnight. Run SET odps.sql.timezone=UTC; in each query session or configure your BI tool’s session time zone. Alibaba cautions against changing the project time zone on an active project.
What are the hourly partition limits?
Two different limits apply:
- 60,000 partitions per table (about 6.8 years of hourly partitions) is table capacity. Once reached, a
LOADrequiring a new partition fails. Plan retention or partition cleanup before reaching it. - 10,000 partitions per query (about 14 months of hourly partitions for a full-history scan) limits your queries, not RudderStack loads. Filter or split queries that span more partitions.
Daily partitions have no practical ceiling for this use case. Partition type is fixed at creation, so choose hourly only if you can manage these limits.
Why does credential or OSS validation fail before the project is checked?
The first validation step checks object storage. A wrong AccessKey, or a newly created key that hasn’t activated yet, fails there before any MaxCompute project check. If your OSS directory path falls outside the policy’s object resource or listing prefix, validation returns oss_access_denied: check the OSS directory path and the policy’s resource scope. With cleanup on, also check oss:DeleteObject access.
Why does validation fail with “MaxCompute schema is not owned by the current principal”?
RudderStack only loads into a schema owned by the identity it connects as. If you change the destination’s MaxCompute account to a different identity (for example, from Access key to RAM role, or to a different role or RAM user), the existing schema still belongs to the previous identity, and validation fails. Rotating the AccessKey of the same RAM user isn’t affected. To switch identity, transfer the schema’s ownership to the new identity in MaxCompute, or create a new destination with a new namespace.
Why is there a rudder-test-payload/ object in OSS?
Each connection test leaves one small rudder-test-payload/… object under your configured OSS directory path from the load-table check. This also happens with other RudderStack warehouse destinations. It’s safe to delete.
Can I query nested objects as JSON documents?
No. Nested objects flatten into table columns, rather than a native JSON document. Property-heavy events can exhaust RudderStack’s 1,200-column limit even though a single event may carry up to 1,600 columns. Plan event properties to keep the table’s column count within the limit.
For general warehouse questions, see Warehouse Destinations FAQ.