Vertex AI Feature Store Is the Production Loop

A production-focused Vertex AI post on turning raw data, BigQuery features, online feature serving, model endpoints, monitoring, and retraining into one governed ML loop instead of another platform checklist.

By Jovani Pink December 30, 2025 12 min — Platform & AI Engineering

Outcome focus: Defined a concrete Vertex AI feature-serving loop with source contracts, BigQuery feature views, point-in-time training exports, endpoint serving rules, monitoring thresholds, and retraining triggers.

A Vertex AI system can look complete and still fail at the feature boundary.

The notebook trained. The metric looked good. The model was uploaded. The endpoint returned predictions. The dashboard said the service was healthy.

Then the real application called the model with features that did not mean the same thing as the training data.

That is the production failure I care about with Vertex AI. It is rarely "can Google Cloud run the training job?" It can. It is rarely "can Vertex AI host the model?" It can. The fragile part is whether the data that taught the model and the data that serves the model follow the same contract.

I already have a broader post on Vertex AI as an MLOps map. This one narrows the lens to the loop that makes many ML systems operational: ingest data, engineer features, serve those features, train from the same definitions, deploy the model, monitor the behavior, and retrain only when the evidence says the decision path changed.

Feature Store is not the whole platform.

It is the part that forces the platform to admit whether "feature" means anything precise.

The Current Vertex AI Reality#

The older six-step Vertex AI summary is still useful:

  1. define the problem,
  2. choose the development environment,
  3. prepare and explore data,
  4. train and evaluate the model,
  5. tune hyperparameters,
  6. deploy for online or batch prediction.

That sequence is correct, but it is too flat for production work. It makes the lifecycle sound like a handoff line. Real ML systems loop.

The production shape is a loop. Feature definitions must connect training, serving, monitoring, and retraining.

Google's current Vertex AI Feature Store overview matters here because the service is BigQuery-centered. Feature data lives in BigQuery tables or views. Those BigQuery sources collectively form the offline store. Feature Store acts as a managed metadata and online-serving layer that can serve the latest values from those BigQuery sources at low latency.

That design is good for Google Cloud teams because BigQuery is often where governance, lineage, SQL review, access control, and batch history already live.

It also removes an excuse. If the feature definition is sloppy in BigQuery, Feature Store will not magically make it trustworthy.

Start With the Decision, Not the Feature#

The first artifact I want is not a notebook.

It is a decision statement:

decision-contract.yaml
decision_path: "same-day retention offer"
user: "retention specialist"
decision_frequency: "hourly"
prediction: "customer churn risk in the next 14 days"
action: "offer outreach, suppress outreach, or route to manual review"
success_metric: "save rate after outreach"
guardrail_metrics:
  opt_out_rate: "<= 2.5%"
  manual_review_overload: "<= 120 cases per day"
  high_value_false_negative_rate: "monitored weekly"

That contract makes feature work concrete.

For a fraud model, freshness may matter more than historical completeness. For a churn model, stable identity and time windows may matter more than millisecond serving latency. For a Gemini support assistant, structured customer facts may be used as context for answer grounding or routing, not as direct supervised model inputs.

Different decisions need different feature contracts.

If the team cannot name the decision, the Feature Store design will drift into "store everything useful." That is a warehouse instinct, not an ML serving strategy.

Step 1: Ingest Data With Producer Contracts#

The source list from the notes is right:

  • BigQuery for structured warehouse data,
  • Cloud Storage for files, exports, images, and intermediate artifacts,
  • Pub/Sub for streaming events,
  • Firestore or Firebase for application state,
  • Dataflow for batch and streaming transformations.

The missing production question is ownership.

Who owns the upstream event? Who can change the schema? Which timestamp is authoritative? What does late-arriving data do? How fresh does the feature need to be? Which identifiers are stable enough to join?

I would capture source contracts before feature engineering:

source-contract.yaml
source: "bigquery://app_events.customer_activity"
producer: "digital product analytics"
owner_group: "data-platform-product-events"
grain: "one row per customer event"
primary_keys:
  - event_id
join_keys:
  - customer_id
time_columns:
  event_time: "when the customer action happened"
  ingest_time: "when the platform received the event"
freshness_sla_minutes: 30
breaking_change_notice_days: 7
privacy_classification: "customer behavioral data"

This looks like paperwork until the first model behaves strangely because event_time and ingest_time were swapped in one pipeline.

That is an old ML failure wearing cloud-native clothes.

Step 2: Engineer Features Where the Data Lives#

Feature engineering turns raw source data into model-ready signals.

On Google Cloud, the usual pattern is:

  • use BigQuery SQL for warehouse-native batch features,
  • use Dataflow for scalable batch or streaming transformations,
  • use Cloud Functions or Cloud Run for small event-driven transformations when the logic is narrow,
  • write results back to BigQuery when the feature needs history, auditability, and training reuse.

An illustrative BigQuery feature table might look like this:

customer_features.sql
CREATE OR REPLACE TABLE ml_features.customer_churn_features AS
SELECT
  customer_id,
  TIMESTAMP_TRUNC(event_time, HOUR) AS feature_timestamp,
  COUNTIF(event_name = 'session_start') AS sessions_24h,
  COUNTIF(event_name = 'support_ticket_created') AS support_tickets_24h,
  SUM(purchase_amount) AS purchase_amount_24h,
  MAX(event_time) AS latest_event_time
FROM app_events.customer_activity
WHERE event_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 24 HOUR)
GROUP BY customer_id, feature_timestamp;

The SQL is intentionally simple. The important fields are customer_id and feature_timestamp.

An online prediction needs the latest value. A training set needs historical values as they were known at the decision time. Without a feature timestamp, the team cannot reason cleanly about freshness or leakage.

The most expensive feature bug is not a syntax error.

It is a feature that accidentally sees the future.

Step 3: Treat Feature Store as a Serving Boundary#

Vertex AI Feature Store is often introduced as a place to store, manage, share, and serve ML features. That is true, but the current BigQuery-backed design should change how teams think about it.

The warehouse remains the historical source. Feature Store provides the online-serving resources and metadata that make feature values available for low-latency prediction.

So the contract should name both sides:

feature-contract.yaml
feature_group: "customer_churn"
entity_key: "customer_id"
offline_source: "bigquery://ml_features.customer_churn_features"
online_serving: "Vertex AI Feature Store feature view"
features:
  sessions_24h:
    type: "integer"
    null_policy: "default_zero"
    freshness_sla_minutes: 60
  support_tickets_24h:
    type: "integer"
    null_policy: "default_zero"
    freshness_sla_minutes: 60
  purchase_amount_24h:
    type: "numeric"
    null_policy: "default_zero"
    freshness_sla_minutes: 60
required_for_online_prediction:
  - sessions_24h
  - support_tickets_24h
  - purchase_amount_24h

At this boundary, the team decides whether a missing feature blocks prediction, falls back to a default, or routes to a rules baseline. The platform can serve values. The team owns the semantics.

Feature reuse is valuable, but reuse without meaning is a trap. If two models use customer_value_score, they need the same definition, timestamp behavior, null policy, and owner. Otherwise the feature name is only a coincidence.

Step 4: Export Training Data With Point-in-Time Semantics#

Training data is not just a batch dump.

It should represent what the model would have known at the decision time.

An illustrative training export might join labels to feature snapshots like this:

training_export.sql
CREATE OR REPLACE TABLE ml_training.churn_training_2026_04 AS
SELECT
  labels.customer_id,
  labels.decision_time,
  labels.churned_within_14_days,
  features.sessions_24h,
  features.support_tickets_24h,
  features.purchase_amount_24h
FROM ml_labels.customer_churn_labels AS labels
JOIN ml_features.customer_churn_features AS features
  ON labels.customer_id = features.customer_id
 AND features.feature_timestamp <= labels.decision_time
QUALIFY ROW_NUMBER() OVER (
  PARTITION BY labels.customer_id, labels.decision_time
  ORDER BY features.feature_timestamp DESC
) = 1;

That QUALIFY pattern is the heart of the example. It chooses the most recent feature row that existed before the decision.

If a training query instead grabs the latest feature value from today for a label from last month, the validation metric will lie. The model gets to learn from future information. The endpoint will never have that advantage.

Feature Store helps with consistency when the offline source, online serving path, and training export are governed together. It does not rescue a training set that was assembled with leakage.

Step 5: Train, Tune, and Register the Model#

Vertex AI gives teams several training paths.

The custom training overview says Vertex AI can run training applications based on any ML framework on Google Cloud infrastructure, with integrated support for PyTorch, TensorFlow, scikit-learn, and XGBoost. The custom training beginner's guide also calls out prebuilt containers for those frameworks and custom containers when your dependencies need to be packaged directly.

For many enterprise use cases, that flexibility is the right default. Use AutoML when the use case fits the managed path and speed matters more than model internals. Use custom training when architecture, dependencies, preprocessing, explainability strategy, or serving behavior need tighter control. Use BigQuery ML when the model belongs close to the warehouse and SQL-based operations are the cleanest path.

Hyperparameter tuning is useful after the baseline is stable. Vertex AI hyperparameter tuning runs multiple trials with different hyperparameter values and reports the best configuration according to the objective you specify. It uses Google Cloud processing infrastructure, but it still needs a meaningful metric, limits, and search budget.

An operating rule I like:

training-gate.yaml
baseline_required_before_tuning: true
experiment_tracking: "Vertex AI Experiments"
registry: "Vertex AI Model Registry"
promotion_metric:
  auc: ">= 0.82"
  calibration_error: "<= 0.04"
business_guardrail:
  review_queue_volume: "<= 120 per day"
container_policy:
  prebuilt_allowed: true
  custom_container_digest_required: true

Do not tune a model before the problem, label, split strategy, and promotion metric are stable. Otherwise hyperparameter tuning optimizes uncertainty.

Step 6: Deploy the Model, Then Assemble the Prediction#

The Vertex AI endpoint deployment docs are direct: before getting online inferences from a trained model, you deploy it to an endpoint. Deployment associates resources with the model so it can serve low-latency online predictions. You choose the endpoint, model container, deployed-model compute resources, and related serving settings.

That is only the model-serving side.

In a feature-driven online prediction flow, the application also needs current feature values.

prediction_flow.py
def predict_churn(request: PredictionRequest) -> PredictionResponse:
    entity_id = request.customer_id
 
    # Schematic pseudocode: fetch the governed online feature values for the entity.
    features = feature_store.fetch_latest(
        feature_view="customer_churn",
        entity_id=entity_id,
        names=["sessions_24h", "support_tickets_24h", "purchase_amount_24h"],
    )
 
    if features.missing_required_values:
        return route_to_rules_baseline(request, reason="missing_required_feature")
 
    instance = {
        "sessions_24h": features["sessions_24h"],
        "support_tickets_24h": features["support_tickets_24h"],
        "purchase_amount_24h": features["purchase_amount_24h"],
        "plan_type": request.plan_type,
    }
 
    prediction = vertex_endpoint.predict(instances=[instance])
    return format_prediction(prediction)

The code is schematic, not a copy-paste SDK example. The architecture decision is the useful part: the endpoint call is not the whole serving path. Feature lookup, missing-value behavior, request validation, auth, latency budget, logging, and fallback all belong in the online prediction design.

For batch prediction, the shape changes. Vertex AI batch inference is for asynchronous scoring against known input sets, often from Cloud Storage or BigQuery. Batch jobs do not have the same autoscaling behavior as online endpoints because the input set is known when the job starts. That affects cost and delivery expectations.

Online and batch are not maturity levels. They are different serving modes.

Step 7: Monitor Features, Model Behavior, and the Business Decision#

Vertex AI Model Monitoring can track tabular model quality signals such as training-serving skew and inference drift. Skew compares production feature distributions against training data. Drift compares current production input distributions against past production distributions. When configured thresholds are crossed, monitoring can alert the team.

That is necessary, not sufficient.

For this loop, I want three monitoring layers:

monitoring-contract.yaml
feature_health:
  freshness_sla_minutes: 60
  required_feature_null_rate: "<= 0.5%"
  online_lookup_error_rate: "<= 0.1%"
 
model_health:
  feature_skew_detection: "enabled"
  prediction_drift_detection: "enabled"
  endpoint_p95_latency_ms: "<= 250"
  endpoint_error_rate: "<= 0.5%"
 
business_health:
  save_rate_after_outreach: "weekly review"
  opt_out_rate: "<= 2.5%"
  manual_review_volume: "<= 120 per day"
 
retraining_trigger:
  - "drift threshold crossed for two consecutive windows"
  - "business metric degrades beyond agreed tolerance"
  - "source contract changes"
  - "label definition changes"

The model can be technically healthy and operationally wrong.

If the churn model is calibrated but the retention team cannot handle the review volume, the system is not working. If feature drift is stable but customer policy changed, the model may still need retraining. If the endpoint is fast but missing-feature fallback is triggered too often, the serving design is not trustworthy.

Retraining should be a decision, not a reflex. Vertex AI Pipelines can automate and govern repeated ML workflows using Kubeflow Pipelines or TFX, and pipeline runs can be associated with experiments. That makes retraining reproducible. It does not decide whether retraining is justified.

Where Gemini Fits#

Your professional focus includes Google Cloud, Vertex AI, Gemini, and AI. That is the right cluster, but it is important not to blur the operating surfaces.

Vertex AI's generative AI docs position Vertex AI as the enterprise platform for Gemini models and other Google, partner, and open models through Model Garden and related tooling. Google's Gemini product page distinguishes AI Studio, Vertex AI, and Gemini Enterprise: Vertex AI is the managed development platform for building with Gemini and third-party models at scale; Gemini Enterprise is the front door for organization-wide AI workflows.

Predictive ML features and Gemini context are not identical, but the discipline rhymes.

A Gemini customer-support assistant may need structured context:

gemini-context-contract.yaml
workflow: "support response drafting"
model_surface: "Gemini API in Vertex AI"
structured_context:
  customer_tier:
    source: "BigQuery governed customer table"
    freshness_sla_hours: 24
  open_case_count:
    source: "support case feature view"
    freshness_sla_minutes: 15
retrieval_context:
  corpus: "approved support knowledge base"
  access_filter: "product and region"
tool_policy:
  create_refund: "human approval required"
  update_case: "allowed after draft approval"
evaluation:
  hallucinated_policy_rate: "<= 1%"
  unsafe_action_rate: "0"

For Gemini systems, the artifact may be a prompt, retrieval policy, tool permission, context bundle, evaluation set, safety threshold, or agent routing rule. For predictive ML systems, the artifact may be a feature view, training table, model version, endpoint, or monitoring job.

Both need owners, evidence, and promotion gates.

That is the platform story worth telling publicly: Google Cloud gives a strong AI control plane, but professional AI engineering is the work of turning platform primitives into governed decision systems.

The Security Layer Is Part of the Design#

The notes mention VPC peering, VPC Service Controls, and customer-managed encryption keys. Keep that instinct.

For production Vertex AI systems, I would make security visible in the contract:

security-contract.yaml
service_accounts:
  training: "vertex-training-sa"
  serving: "vertex-serving-sa"
  pipeline: "vertex-pipeline-sa"
iam:
  least_privilege: true
  separate_training_and_serving_identities: true
network:
  private_endpoint_required: true
  vpc_service_controls: "evaluate for regulated data"
encryption:
  cmek_required: true
data_controls:
  no_raw_pii_in_prompts: true
  feature_tables_policy_tagged: true
audit:
  log_endpoint_requests: true
  log_feature_lookup_failures: true

The exact controls depend on the organization, data class, and workload. The mistake is treating security as a late review after the feature serving path is already built.

What I Would Build First#

For a first production-grade Vertex AI system, I would not enable every service and call it architecture.

I would build one narrow loop:

  1. one decision path,
  2. one governed BigQuery feature table,
  3. one point-in-time training export,
  4. one baseline model,
  5. one registered candidate,
  6. one serving endpoint or batch job,
  7. one monitoring contract,
  8. one retraining rule.

Then I would add Vertex AI Feature Store when online feature serving or reuse justifies the boundary. I would add Pipelines when repetition and promotion evidence become the risk. I would add hyperparameter tuning when the baseline and metric are stable. I would add Gemini where the workflow needs generation, reasoning, summarization, tool use, or multimodal interaction, not because every AI system needs a chatbot.

The professional move is not knowing every Google Cloud AI product name.

The professional move is knowing which boundary each product should own.

Vertex AI Feature Store becomes valuable when it connects training truth, online serving, monitoring, and retraining into one feature contract. Without that contract, it is just another impressive box in a diagram.

Build the loop. Then scale the platform.

Back to all writing
On this page
  1. The Current Vertex AI Reality
  2. Start With the Decision, Not the Feature
  3. Step 1: Ingest Data With Producer Contracts
  4. Step 2: Engineer Features Where the Data Lives
  5. Step 3: Treat Feature Store as a Serving Boundary
  6. Step 4: Export Training Data With Point-in-Time Semantics
  7. Step 5: Train, Tune, and Register the Model
  8. Step 6: Deploy the Model, Then Assemble the Prediction
  9. Step 7: Monitor Features, Model Behavior, and the Business Decision
  10. Where Gemini Fits
  11. The Security Layer Is Part of the Design
  12. What I Would Build First